-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Command to send debug emails, and documentation of email development …
…workflow (#2838) * Fix missing async awaits in email pathways * sendDebugEmail command * Make nodemailer secure option configurable in env vars * Update email development docs * Add more graceful cancellation of sending --------- Co-authored-by: TylerHendrickson <[email protected]>
- Loading branch information
1 parent
658294a
commit 2b0faf1
Showing
13 changed files
with
160 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Email Setup | ||
|
||
## Ethereal Mail Setup (sandboxed email environment) | ||
|
||
[Ethereal](https://ethereal.email/) is the recommended way to set up your development environment to work on emails. | ||
|
||
Ethereal is a free "fake" SMTP sandbox service. You can instantly create a temporary email account that pretends it can send and receive emails. Emails received and "sent" by this temporary account can be viewed in the messages inbox, but the address will never actually send anything outbound. This makes it a much safer way to test email sending in development. | ||
|
||
1. Go to [Ethereal](https://ethereal.email/) and click "Create Ethereal Account". | ||
|
||
![Ethereal homepage](./img/setup-email-ethereal.png) | ||
|
||
2. Find the SMTP Configuration details for the new account on the created page. | ||
|
||
![SMTP configuration details](./img/setup-email-smtp-configuration.png) | ||
|
||
3. Update your `NODEMAILER_*` environment variables in your `server/.env` file with the SMTP details. | ||
- `NODEMAILER_HOST=smtp.ethereal.email` | ||
- `NODEMAILER_PORT=587` | ||
- `NODEMAILER_SECURE=false` — Ethereal doesn't use a secure SMTP connection, so you'll turn secure off here | ||
- `NODEMAILER_EMAIL={{ email }}` — set the new email address from Ethereal's SMTP details here | ||
- `NODEMAILER_EMAIL_PW={{ password }}` — set the new password from Ethereal's SMTP details here | ||
4. Rebuild your app docker container so it picks up the new environment variables | ||
- `docker compose down app` | ||
- `docker compose up -d` | ||
5. Use the send debug email tool to send a demo of any email type for your Ethereal email to capture | ||
- `docker compose exec app yarn workspace server run send-debug-email` | ||
6. Click over to the "Messages" tab on Ethereal to see your inbox and view the message | ||
|
||
![Ethereal inbox](./img/setup-email-ethereal-inbox.png) | ||
![Ehtereal message](./img/setup-email-ethereal-welcome.png) | ||
|
||
## Gmail Setup (DANGER — live email environment) | ||
|
||
> [!WARNING] | ||
> Gmail setup is generally not required for local development. Note that with this setup you will send real emails — please ensure you don't have real external email addresses in your database that you could accidentally mail. Please revert these environment variables to disable email sending anytime you're not actively intending to send real email. | ||
Users log into the app by means of a single-use link that is sent to their email. In order to set your app up to send this email, you'll need to setup an App Password in Gmail. | ||
|
||
Visit: <https://myaccount.google.com/apppasswords> and set up an "App Password" (see screenshot below). *Note: Select "Mac" even if you're not using a Mac.* | ||
|
||
In `packages/server/.env`, set `NODEMAILER_EMAIL` to your email/gmail and set your `NODEMAILER_EMAIL_PW` to the new generated PW. | ||
|
||
**Note:** Environment variable changes will require rebuilding your docker container to be picked up. | ||
|
||
![Gmail App Password screen](./img/gmail-app-password.png) | ||
|
||
**NOTE:** In order to enable App Password MUST turn on 2FA for gmail. | ||
|
||
If running into `Error: Invalid login: 535-5.7.8 Username and Password not accepted.` then ["Allow Less Secure Apps"](https://myaccount.google.com/lesssecureapps) - [source](https://stackoverflow.com/a/59194512) | ||
|
||
**NOTE:** Much more reliable and preferable to go the App Password route vs Less Secure Apps. | ||
|
||
![Email Error](./img/error-gmail.png) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ [email protected] | |
# Email Server: | ||
NODEMAILER_HOST=smtp.gmail.com | ||
NODEMAILER_PORT=465 | ||
NODEMAILER_SECURE=true | ||
NODEMAILER_EMAIL=[email protected] | ||
NODEMAILER_EMAIL_PW="" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#!/usr/bin/env node | ||
const inquirer = require('inquirer'); | ||
const knex = require('../db/connection'); | ||
const { TABLES } = require('../db/constants'); | ||
const db = require('../db'); | ||
const email = require('../lib/email'); | ||
const seedGrants = require('../../seeds/dev/ref/grants'); | ||
const seedUsers = require('../../seeds/dev/ref/users'); | ||
|
||
async function sendWelcome() { | ||
await email.sendWelcomeEmail( | ||
'[email protected]', | ||
process.env.WEBSITE_DOMAIN, | ||
); | ||
} | ||
|
||
async function sendPassCode() { | ||
const loginEmail = '[email protected]'; | ||
const passcode = await db.createAccessToken(loginEmail); | ||
await email.sendPassCode( | ||
loginEmail, | ||
passcode, | ||
process.env.WEBSITE_DOMAIN, | ||
null, | ||
); | ||
} | ||
|
||
async function sendGrantDigest() { | ||
const grantIds = seedGrants.grants.slice(0, 3).map((grant) => grant.grant_id); | ||
const grants = await knex(TABLES.grants).whereIn('grant_id', grantIds); | ||
await email.sendGrantDigest({ | ||
name: 'Test agency', | ||
matchedGrants: grants, | ||
matchedGrantsTotal: grantIds.length, | ||
recipients: ['[email protected]'], | ||
openDate: '2024-01-01', | ||
}); | ||
} | ||
|
||
async function sendGrantAssigned() { | ||
// Use Dallas since there's only one user in the agency, so we should get only 1 email sent | ||
const user = seedUsers.find((seedUser) => seedUser.email === '[email protected]'); | ||
await email.sendGrantAssignedEmail({ | ||
grantId: seedGrants.grants[0].grant_id, | ||
agencyIds: [user.agency_id], | ||
userId: user.id, | ||
}); | ||
} | ||
|
||
async function sendAsyncReport() { | ||
await email.sendAsyncReportEmail( | ||
'[email protected]', | ||
`${process.env.API_DOMAIN}/api/audit_report/fake_key`, | ||
'Audit', | ||
); | ||
} | ||
|
||
async function sendReportError() { | ||
const userId = seedUsers.find((seedUser) => seedUser.email === '[email protected]').id; | ||
const user = await db.getUser(userId); | ||
await email.sendReportErrorEmail(user, 'Audit'); | ||
} | ||
|
||
const emailTypes = { | ||
'new user welcome': sendWelcome, | ||
'login passcode': sendPassCode, | ||
'grant digest': sendGrantDigest, | ||
'grant assigned': sendGrantAssigned, | ||
'report generation completed': sendAsyncReport, | ||
'report generation failed': sendReportError, | ||
}; | ||
|
||
async function main() { | ||
const answers = await inquirer.prompt([ | ||
{ name: 'emailType', type: 'list', choices: Object.keys(emailTypes) }, | ||
]); | ||
try { | ||
const sendEmail = emailTypes[answers.emailType]; | ||
await sendEmail(); | ||
} catch (e) { | ||
console.error('Error sending email. Have you run the DB seed?', e); | ||
} | ||
} | ||
|
||
if (require.main === module) { | ||
process.on('SIGINT', () => { | ||
console.log('Exiting.'); | ||
process.exit(); | ||
}); | ||
main().then(() => process.exit()); | ||
} |