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
|
BabelEdit project file
|
||||||
@@ -1233,6 +1233,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</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>
|
<concept_node>
|
||||||
<name>subject</name>
|
<name>subject</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Table } from "antd";
|
import { Table } from "antd";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import React, { useState } from "react";
|
||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
|
||||||
import { useTranslation } from "react-i18next";
|
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 }) {
|
export default function EmailAuditTrailListComponent({ loading, data }) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ export function JobAuditTrail({ currentUser, jobId }) {
|
|||||||
dataIndex: "subject",
|
dataIndex: "subject",
|
||||||
key: "subject",
|
key: "subject",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("audit.fields.status"),
|
||||||
|
dataIndex: "status",
|
||||||
|
key: "status",
|
||||||
|
},
|
||||||
...(currentUser?.email.includes("@imex.")
|
...(currentUser?.email.includes("@imex.")
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
"contents": "Contents",
|
"contents": "Contents",
|
||||||
"created": "Time",
|
"created": "Time",
|
||||||
"operation": "Operation",
|
"operation": "Operation",
|
||||||
|
"status": "Status",
|
||||||
"subject": "Subject",
|
"subject": "Subject",
|
||||||
"to": "To",
|
"to": "To",
|
||||||
"useremail": "User",
|
"useremail": "User",
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
"contents": "",
|
"contents": "",
|
||||||
"created": "",
|
"created": "",
|
||||||
"operation": "",
|
"operation": "",
|
||||||
|
"status": "",
|
||||||
"subject": "",
|
"subject": "",
|
||||||
"to": "",
|
"to": "",
|
||||||
"useremail": "",
|
"useremail": "",
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
"contents": "",
|
"contents": "",
|
||||||
"created": "",
|
"created": "",
|
||||||
"operation": "",
|
"operation": "",
|
||||||
|
"status": "",
|
||||||
"subject": "",
|
"subject": "",
|
||||||
"to": "",
|
"to": "",
|
||||||
"useremail": "",
|
"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
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
columns:
|
columns:
|
||||||
- cc
|
|
||||||
- to
|
|
||||||
- contents
|
|
||||||
- subject
|
|
||||||
- useremail
|
|
||||||
- created_at
|
|
||||||
- updated_at
|
|
||||||
- bodyshopid
|
- bodyshopid
|
||||||
|
- cc
|
||||||
|
- contents
|
||||||
|
- created_at
|
||||||
- id
|
- id
|
||||||
- jobid
|
- jobid
|
||||||
- noteid
|
- noteid
|
||||||
|
- status
|
||||||
|
- status_context
|
||||||
|
- subject
|
||||||
|
- to
|
||||||
|
- updated_at
|
||||||
|
- useremail
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -3139,6 +3141,7 @@
|
|||||||
- po_number
|
- po_number
|
||||||
- policy_no
|
- policy_no
|
||||||
- production_vars
|
- production_vars
|
||||||
|
- qb_multiple_payers
|
||||||
- queued_for_parts
|
- queued_for_parts
|
||||||
- rate_ats
|
- rate_ats
|
||||||
- rate_la1
|
- rate_la1
|
||||||
@@ -3401,6 +3404,7 @@
|
|||||||
- po_number
|
- po_number
|
||||||
- policy_no
|
- policy_no
|
||||||
- production_vars
|
- production_vars
|
||||||
|
- qb_multiple_payers
|
||||||
- queued_for_parts
|
- queued_for_parts
|
||||||
- rate_ats
|
- rate_ats
|
||||||
- rate_la1
|
- rate_la1
|
||||||
@@ -3673,6 +3677,7 @@
|
|||||||
- po_number
|
- po_number
|
||||||
- policy_no
|
- policy_no
|
||||||
- production_vars
|
- production_vars
|
||||||
|
- qb_multiple_payers
|
||||||
- queued_for_parts
|
- queued_for_parts
|
||||||
- rate_ats
|
- rate_ats
|
||||||
- rate_la1
|
- 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.
|
//Email Based Paths.
|
||||||
var sendEmail = require("./server/email/sendemail.js");
|
var sendEmail = require("./server/email/sendemail.js");
|
||||||
app.post("/sendemail", fb.validateFirebaseIdToken, sendEmail.sendEmail);
|
app.post("/sendemail", fb.validateFirebaseIdToken, sendEmail.sendEmail);
|
||||||
|
app.post(
|
||||||
|
"/emailbounce",
|
||||||
|
bodyParser.text(),
|
||||||
|
sendEmail.emailBounce
|
||||||
|
);
|
||||||
|
|
||||||
//Test route to ensure Express is responding.
|
//Test route to ensure Express is responding.
|
||||||
app.get("/test", async function (req, res) {
|
app.get("/test", async function (req, res) {
|
||||||
@@ -238,7 +243,6 @@ app.get("/", async function (req, res) {
|
|||||||
res.status(200).send("Access Forbidden.");
|
res.status(200).send("Access Forbidden.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.listen(port, (error) => {
|
server.listen(port, (error) => {
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
logger.log(
|
logger.log(
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ exports.sendEmail = async (req, res) => {
|
|||||||
to: req.body.to,
|
to: req.body.to,
|
||||||
cc: req.body.cc,
|
cc: req.body.cc,
|
||||||
subject: req.body.subject,
|
subject: req.body.subject,
|
||||||
|
messageId: info.messageId,
|
||||||
});
|
});
|
||||||
res.json({
|
res.json({
|
||||||
success: true, //response: info
|
success: true, //response: info
|
||||||
@@ -190,6 +191,8 @@ async function logEmail(req, email) {
|
|||||||
useremail: req.user.email,
|
useremail: req.user.email,
|
||||||
contents: req.body.html,
|
contents: req.body.html,
|
||||||
jobid: req.body.jobid,
|
jobid: req.body.jobid,
|
||||||
|
sesmessageid: email.messageId,
|
||||||
|
status: "Sent",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} 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