-
-
Notifications
You must be signed in to change notification settings - Fork 625
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Support for Alternate Email Transports (#1580)
* Add support for AWS SES and SMTP email transports Signed-off-by: Erin Allison <[email protected]> * Correct environment variable names for new email settings Signed-off-by: Erin Allison <[email protected]> * Correct option names being passed to nodemailer for SMTP Signed-off-by: Erin Allison <[email protected]> * Remove use of AWS SDK synthetic default export It apparently causes issues when transpiled/bundled Signed-off-by: Erin Allison <[email protected]> * Add documentation for new email settings Signed-off-by: Erin Allison <[email protected]> * Move nodemailer types to devDependencies Signed-off-by: Erin Allison <[email protected]> * Adjust mail transport error handling Gotta keep the linter happy :) Signed-off-by: Erin Allison <[email protected]> * Fix typecheck error on MailTransportOptions Signed-off-by: Erin Allison <[email protected]> * Correct environment variable usage for SMTP email transport Signed-off-by: Erin Allison <[email protected]> --------- Signed-off-by: Erin Allison <[email protected]>
- Loading branch information
1 parent
21a4fab
commit 4d2412a
Showing
12 changed files
with
1,286 additions
and
65 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
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import type { DeliverEmail, SendPlainTextOptions } from "emails"; | ||
import { EmailClient } from "emails"; | ||
import { EmailClient, MailTransportOptions } from "emails"; | ||
import type { SendEmailOptions } from "remix-auth-email-link"; | ||
import { redirect } from "remix-typedjson"; | ||
import { env } from "~/env.server"; | ||
|
@@ -13,7 +13,7 @@ const client = singleton( | |
"email-client", | ||
() => | ||
new EmailClient({ | ||
apikey: env.RESEND_API_KEY, | ||
transport: buildTransportOptions(), | ||
imagesBaseUrl: env.APP_ORIGIN, | ||
from: env.FROM_EMAIL ?? "[email protected]", | ||
replyTo: env.REPLY_TO_EMAIL ?? "[email protected]", | ||
|
@@ -24,13 +24,45 @@ const alertsClient = singleton( | |
"alerts-email-client", | ||
() => | ||
new EmailClient({ | ||
apikey: env.ALERT_RESEND_API_KEY, | ||
transport: buildTransportOptions(true), | ||
imagesBaseUrl: env.APP_ORIGIN, | ||
from: env.ALERT_FROM_EMAIL ?? "[email protected]", | ||
replyTo: env.REPLY_TO_EMAIL ?? "[email protected]", | ||
}) | ||
); | ||
|
||
function buildTransportOptions(alerts?: boolean): MailTransportOptions { | ||
const transportType = alerts ? env.ALERT_EMAIL_TRANSPORT : env.EMAIL_TRANSPORT | ||
logger.debug(`Constructing email transport '${transportType}' for usage '${alerts?'alerts':'general'}'`) | ||
|
||
switch (transportType) { | ||
case "aws-ses": | ||
return { type: "aws-ses" }; | ||
case "resend": | ||
return { | ||
type: "resend", | ||
config: { | ||
apiKey: alerts ? env.ALERT_RESEND_API_KEY : env.RESEND_API_KEY, | ||
} | ||
} | ||
case "smtp": | ||
return { | ||
type: "smtp", | ||
config: { | ||
host: alerts ? env.ALERT_SMTP_HOST : env.SMTP_HOST, | ||
port: alerts ? env.ALERT_SMTP_PORT : env.SMTP_PORT, | ||
secure: alerts ? env.ALERT_SMTP_SECURE : env.SMTP_SECURE, | ||
auth: { | ||
user: alerts ? env.ALERT_SMTP_USER : env.SMTP_USER, | ||
pass: alerts ? env.ALERT_SMTP_PASSWORD : env.SMTP_PASSWORD | ||
} | ||
} | ||
}; | ||
default: | ||
return { type: undefined }; | ||
} | ||
} | ||
|
||
export async function sendMagicLinkEmail(options: SendEmailOptions<AuthUser>): Promise<void> { | ||
// Auto redirect when in development mode | ||
if (env.NODE_ENV === "development") { | ||
|
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,67 @@ | ||
import { render } from "@react-email/render"; | ||
import { EmailError, MailMessage, MailTransport, PlainTextMailMessage } from "./index"; | ||
import nodemailer from "nodemailer" | ||
import * as awsSes from "@aws-sdk/client-ses" | ||
|
||
export type AwsSesMailTransportOptions = { | ||
type: 'aws-ses', | ||
} | ||
|
||
export class AwsSesMailTransport implements MailTransport { | ||
#client: nodemailer.Transporter; | ||
|
||
constructor(options: AwsSesMailTransportOptions) { | ||
const ses = new awsSes.SESClient() | ||
|
||
this.#client = nodemailer.createTransport({ | ||
SES: { | ||
aws: awsSes, | ||
ses | ||
} | ||
}) | ||
} | ||
|
||
async send({to, from, replyTo, subject, react}: MailMessage): Promise<void> { | ||
try { | ||
await this.#client.sendMail({ | ||
from: from, | ||
to, | ||
replyTo: replyTo, | ||
subject, | ||
html: render(react), | ||
}); | ||
} | ||
catch (error) { | ||
if (error instanceof Error) { | ||
console.error( | ||
`Failed to send email to ${to}, ${subject}. Error ${error.name}: ${error.message}` | ||
); | ||
throw new EmailError(error); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
|
||
async sendPlainText({to, from, replyTo, subject, text}: PlainTextMailMessage): Promise<void> { | ||
try { | ||
await this.#client.sendMail({ | ||
from: from, | ||
to, | ||
replyTo: replyTo, | ||
subject, | ||
text: text, | ||
}); | ||
} | ||
catch (error) { | ||
if (error instanceof Error) { | ||
console.error( | ||
`Failed to send email to ${to}, ${subject}. Error ${error.name}: ${error.message}` | ||
); | ||
throw new EmailError(error); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.