New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(email): Fix SendGrid fallback integration #1026
Conversation
4e7fbc5
to
901ec2b
Compare
0d7a646
to
3e14970
Compare
We want to log email bounce sub types in email callbacks, here is the relevant pr #1062. Sendgrid provides bounce reasons which can be stored as error sub types too. I have not included this in the pr as we are unable to test the Sendgrid flow right now. Here is the previous code written before I reverted the Sendgrid changes. |
Oh I see, thanks! Since we are unable to test the Sendgrid flow in time, perhaps it should be in a separate PR? |
Update - pending SendGrid account setup before continue on review |
56416c7
to
4beb7ca
Compare
We currently use SendGrid as our email fallback. This causes the following functions to fail: 1. Verifying custom from addresses (e.g. adding a new address, storing a campaign template with a custom address) 2. Sending emails with custom from addresses may not fail, but will not be DKIM-authenticated. Since custom from addresses are not DKIM-authenticated with SendGrid, we shouldn't use them at all with SendGrid. Hence, 1. Send all emails using the default address during the fallback. 2. Disallow verification of custom from addresses during the fallback. 3. Disallow storing of templates using custom from addresses.
Oops... this shouldn't be enabled by default.
SendGrid requires the payload to be parsed in text, byte for byte. Since we parse the payload as JSON using `bodyParser.json()`, we unintentionally strip away the whitespace characters and mess up the encoding. Fix the payload and parse it correctly before verifying the callback.
This is very brittle code and may break in the future without notice. For example, the integration test that SendGrid provides fails the verification, but actual email delivery events pass. Revert it and keep it in the history for reference while investigating a more reliable fix. This reverts commit 68f9bd699000b4dc33d9227ec60bc069a9ac7f65.
24fc80a
to
eec77ff
Compare
// This is to avoid stripping whitespace characters and messing with unicode encoding. | ||
// This route affects SES callbacks as well, so we'll need to parse the text as JSON | ||
// in the parseEvent() handle before parsing the SES event. | ||
app.use('/v1/callback/email', bodyParser.text({ type: 'application/json' })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SendGrid events contain carriage return and newline characters (\r\n
) and some even have unicode-encoded characters. The JSON body-parser that we currently use strips the newline characters and decodes the unicode characters, which causes the ECDSA verification to fail.
I had a less intrusive fix here: 201d0f4
But, I think it's not great for reasons stated in the revert: 5473c72
I ended up with this solution since it isn't super intrusive, but it might affect SES callbacks. I doubt it would in practice though.
One other solution which doesn't affect SES callbacks is to split the SES and SendGrid callback endpoints, and only apply the text body-parser for SendGrid, but that would be sort of a breaking change. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fine. I've checked and only one body-parser
middleware will run each time.
…tances" This reverts commit eec77ff.
…cker instances"" This reverts commit 7f0025a.
…g fallback" A side effect of this is that the email section in the settings tab will be reverted to the request form (like when they don't have a custom from registered). This might cause users to be alarmed that their custom from is now missing. Let's just rely on the error message from the subsequent PUT request. This reverts commit 40228df.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm! Tested the following and works as expected:
- Activation of email fallback should prevent verifying new custom from address
- Activation of email fallback should prevent usage of custom from address
- SendGrid events are parsed and handled correctly
- SES events are parsed and handled correctly
- Sendgrid is able to deliver to SGMail email addresses
* develop: refactor: use shared function to initialize models (#1172) chore: setup scaffolding for backend tests (#940) 1.23.0 fix(frontend): fix frontend test flakiness (#1162) fix: update successful delivery status only if error does not exist (#1150) chore: upgrade dependencies (#1153) feat: add unit tests for error states in critical workflows (#1118) feat: support whitelisting domains through `agencies` table (#1141) feat: add tests for happy paths in critical workflows (#1110) fix: prevent campaign names from causing dashboard rows to overflow (#1147) fix(email): Fix SendGrid fallback integration (#1026)
Problem
We currently use SendGrid as our email fallback. This causes the
following functions to fail:
a campaign template with a custom address)
Closes #1021
Solution
Since custom from addresses are not verified with SendGrid, we shouldn't use
them at all.
In the future, if we do intend to authenticate custom from addresses with SendGrid,
we will also have to rewire
verifyFromAddress()
to use SendGrid APIs.Features:
Before & After Screenshots
Click to show images
AFTER:
Attempting to verify a custom from address:
Attempting to save an email template using a custom from address:
Creating a new email campaign:
Tests
Test 1: all campaign emails should be sent using the default from address during fallback
EMAIL_FALLBACK_ACTIVATE
totrue
for the workerTest 2: verification of custom from addresses should be disabled during fallback
EMAIL_FALLBACK_ACTIVATE
totrue
for the backendTest 3: storing of templates with custom from addresses should be disabled during fallback
EMAIL_FALLBACK_ACTIVATE
totrue
for the backendTest 4: SES callbacks should be received and parsed correctly
STAGING_BRANCH=sendgrid-email-fallback
andDEPLOY_WORKER=true
status
anderror_code
columns of theemail_messages
are updated correctly]Test 5: SendGrid callbacks should be received and parsed correctly
EMAIL_FALLBACK_ACTIVATE=true
on Secrets ManagerBAK_
BAK_
STAGING_BRANCH=sendgrid-email-fallback
andDEPLOY_WORKER=true
bouncetest@tribulant.com
)status
anderror_code
columns of theemail_messages
are updated correctlyDeploy Notes
New environment variables:
EMAIL_FALLBACK_ACTIVATE
: Switch to true to use SendGrid as fallback for all emails. Ensure that the SMTP settings are properly configured as well. (worker and backend)Todo