IO-2061 Handled Bounced Emails.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<babeledit_project be_version="2.7.1" version="1.2">
|
||||
<babeledit_project version="1.2" be_version="2.7.1">
|
||||
<!--
|
||||
|
||||
BabelEdit project file
|
||||
@@ -1233,6 +1233,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>status</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>subject</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { Table } from "antd";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import AuditTrailValuesComponent from "../audit-trail-values/audit-trail-values.component";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
|
||||
export default function EmailAuditTrailListComponent({ loading, data }) {
|
||||
const [state, setState] = useState({
|
||||
@@ -11,7 +10,7 @@ export default function EmailAuditTrailListComponent({ loading, data }) {
|
||||
filteredInfo: {},
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const columns = [
|
||||
const columns = [
|
||||
{
|
||||
title: t("audit.fields.created"),
|
||||
dataIndex: " created",
|
||||
|
||||
@@ -85,6 +85,11 @@ export function JobAuditTrail({ currentUser, jobId }) {
|
||||
dataIndex: "subject",
|
||||
key: "subject",
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
},
|
||||
...(currentUser?.email.includes("@imex.")
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"contents": "Contents",
|
||||
"created": "Time",
|
||||
"operation": "Operation",
|
||||
"status": "Status",
|
||||
"subject": "Subject",
|
||||
"to": "To",
|
||||
"useremail": "User",
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"contents": "",
|
||||
"created": "",
|
||||
"operation": "",
|
||||
"status": "",
|
||||
"subject": "",
|
||||
"to": "",
|
||||
"useremail": "",
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"contents": "",
|
||||
"created": "",
|
||||
"operation": "",
|
||||
"status": "",
|
||||
"subject": "",
|
||||
"to": "",
|
||||
"useremail": "",
|
||||
|
||||
24
hasura/MigrationResolution.md
Normal file
24
hasura/MigrationResolution.md
Normal file
@@ -0,0 +1,24 @@
|
||||
Issue when migrating events resolved by running SQL below. User needed updating when running in prod.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hdb_catalog.hdb_source_catalog_version
|
||||
(
|
||||
version text COLLATE pg_catalog."default" NOT NULL,
|
||||
upgraded_on timestamp with time zone NOT NULL
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE hdb_catalog.hdb_source_catalog_version
|
||||
OWNER to postgres;
|
||||
-- Index: hdb_source_catalog_version_one_row
|
||||
|
||||
-- DROP INDEX hdb_catalog.hdb_source_catalog_version_one_row;
|
||||
|
||||
CREATE UNIQUE INDEX hdb_source_catalog_version_one_row
|
||||
ON hdb_catalog.hdb_source_catalog_version USING btree
|
||||
((version IS NOT NULL) ASC NULLS LAST)
|
||||
TABLESPACE pg_default;
|
||||
|
||||
INSERT INTO hdb_catalog.hdb_source_catalog_version (version, upgraded_on) VALUES ('2', NOW());
|
||||
|
||||
https://devscope.io/code/hasura/graphql-engine/issues/8694
|
||||
@@ -1882,17 +1882,19 @@
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- cc
|
||||
- to
|
||||
- contents
|
||||
- subject
|
||||
- useremail
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- cc
|
||||
- contents
|
||||
- created_at
|
||||
- id
|
||||
- jobid
|
||||
- noteid
|
||||
- status
|
||||
- status_context
|
||||
- subject
|
||||
- to
|
||||
- updated_at
|
||||
- useremail
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
@@ -3139,6 +3141,7 @@
|
||||
- po_number
|
||||
- policy_no
|
||||
- production_vars
|
||||
- qb_multiple_payers
|
||||
- queued_for_parts
|
||||
- rate_ats
|
||||
- rate_la1
|
||||
@@ -3401,6 +3404,7 @@
|
||||
- po_number
|
||||
- policy_no
|
||||
- production_vars
|
||||
- qb_multiple_payers
|
||||
- queued_for_parts
|
||||
- rate_ats
|
||||
- rate_la1
|
||||
@@ -3673,6 +3677,7 @@
|
||||
- po_number
|
||||
- policy_no
|
||||
- production_vars
|
||||
- qb_multiple_payers
|
||||
- queued_for_parts
|
||||
- rate_ats
|
||||
- rate_la1
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."email_audit_trail" add column "sesmessageid" text
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."email_audit_trail" add column "sesmessageid" text
|
||||
null;
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."email_audit_trail_sesmessageid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "email_audit_trail_sesmessageid" on
|
||||
"public"."email_audit_trail" using btree ("sesmessageid");
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."email_audit_trail" add column "status" text
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."email_audit_trail" add column "status" text
|
||||
null;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."email_audit_trail" add column "status_context" jsonb
|
||||
-- null default jsonb_build_array();
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."email_audit_trail" add column "status_context" jsonb
|
||||
null default jsonb_build_array();
|
||||
@@ -64,6 +64,11 @@ app.use(
|
||||
//Email Based Paths.
|
||||
var sendEmail = require("./server/email/sendemail.js");
|
||||
app.post("/sendemail", fb.validateFirebaseIdToken, sendEmail.sendEmail);
|
||||
app.post(
|
||||
"/emailbounce",
|
||||
bodyParser.text(),
|
||||
sendEmail.emailBounce
|
||||
);
|
||||
|
||||
//Test route to ensure Express is responding.
|
||||
app.get("/test", async function (req, res) {
|
||||
@@ -238,7 +243,6 @@ app.get("/", async function (req, res) {
|
||||
res.status(200).send("Access Forbidden.");
|
||||
});
|
||||
|
||||
|
||||
server.listen(port, (error) => {
|
||||
if (error) throw error;
|
||||
logger.log(
|
||||
|
||||
@@ -148,6 +148,7 @@ exports.sendEmail = async (req, res) => {
|
||||
to: req.body.to,
|
||||
cc: req.body.cc,
|
||||
subject: req.body.subject,
|
||||
messageId: info.messageId,
|
||||
});
|
||||
res.json({
|
||||
success: true, //response: info
|
||||
@@ -190,6 +191,8 @@ async function logEmail(req, email) {
|
||||
useremail: req.user.email,
|
||||
contents: req.body.html,
|
||||
jobid: req.body.jobid,
|
||||
sesmessageid: email.messageId,
|
||||
status: "Sent",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -202,3 +205,60 @@ async function logEmail(req, email) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
exports.emailBounce = async function (req, res, next) {
|
||||
try {
|
||||
const body = JSON.parse(req.body);
|
||||
if (body.type === "SubscriptionConfirmation") {
|
||||
logger.log("SNS-confirmation", "DEBUG", "api", null, {
|
||||
message: body.message,
|
||||
url: body.SubscribeUrl,
|
||||
body: body,
|
||||
});
|
||||
}
|
||||
if (body.Type === "Notification") {
|
||||
const message = JSON.parse(body.Message);
|
||||
let replyTo, subject, messageId;
|
||||
message.mail.headers.forEach((header) => {
|
||||
if (header.name === "Reply-To") {
|
||||
replyTo = header.value;
|
||||
} else if (header.name === "Subject") {
|
||||
subject = header.value;
|
||||
} else if (header.name === "Message-ID") {
|
||||
messageId = header.value;
|
||||
}
|
||||
});
|
||||
//If it's bounced, log it as bounced in audit log. Send an email to the user.
|
||||
const result = await client.request(queries.UPDATE_EMAIL_AUDIT, {
|
||||
sesid: messageId,
|
||||
status: "Bounced",
|
||||
context: message.bounce?.bouncedRecipients,
|
||||
});
|
||||
transporter.sendMail(
|
||||
{
|
||||
from: `ImEX Online <noreply@imex.online>`,
|
||||
to: "patrick@snapt.ca", // replyTo,
|
||||
bcc: "patrick@snapt.ca",
|
||||
subject: `ImEX Online Bounced Email - RE: ${subject}`,
|
||||
text: `
|
||||
ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error.
|
||||
|
||||
${message.bounce?.bouncedRecipients.map(
|
||||
(r) =>
|
||||
`Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode}
|
||||
`
|
||||
)}
|
||||
`,
|
||||
},
|
||||
(err, info) => {
|
||||
console.log("***", err || info);
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("sns-error", "ERROR", "api", null, {
|
||||
error: JSON.stringify(error),
|
||||
});
|
||||
}
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
@@ -1621,3 +1621,12 @@ mutation DELETE_DOCUMENTS($ids: [uuid!]!) {
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
exports.UPDATE_EMAIL_AUDIT = `
|
||||
mutation ($sesid: String!, $status: String, $context: jsonb) {
|
||||
update_email_audit_trail(where: {sesmessageid: {_eq: $sesid}}, _set: {status: $status, status_context: $context}) {
|
||||
returning {
|
||||
contents
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
Reference in New Issue
Block a user