mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-17 00:15:28 +02:00
Revert "♻️ Improve email abstraction (#861)"
This reverts commit 93cc5b9b4d
.
This commit is contained in:
parent
93cc5b9b4d
commit
1199ca5c53
10 changed files with 141 additions and 738 deletions
|
@ -3,7 +3,6 @@ import { defaultProvider } from "@aws-sdk/credential-provider-node";
|
|||
import { render } from "@react-email/render";
|
||||
import { createTransport, Transporter } from "nodemailer";
|
||||
import type Mail from "nodemailer/lib/mailer";
|
||||
import previewEmail from "preview-email";
|
||||
import React from "react";
|
||||
|
||||
import * as templates from "./templates";
|
||||
|
@ -18,121 +17,30 @@ type TemplateProps<T extends TemplateName> = React.ComponentProps<
|
|||
|
||||
type TemplateComponent<T extends TemplateName> = Templates[T];
|
||||
|
||||
type SendEmailOptions<T extends TemplateName> = {
|
||||
to: string;
|
||||
subject: string;
|
||||
props: TemplateProps<T>;
|
||||
attachments?: Mail.Options["attachments"];
|
||||
};
|
||||
const env = process.env["NODE" + "_ENV"] || "development";
|
||||
|
||||
type EmailProviderConfig =
|
||||
| {
|
||||
name: "ses";
|
||||
// config defined through env vars
|
||||
}
|
||||
| {
|
||||
name: "smtp";
|
||||
// config defined through env vars
|
||||
};
|
||||
let transport: Transporter;
|
||||
|
||||
export type SupportedEmailProviders = EmailProviderConfig["name"];
|
||||
|
||||
type EmailClientConfig = {
|
||||
/**
|
||||
* Whether to open previews of each email in the browser
|
||||
*/
|
||||
openPreviews?: boolean;
|
||||
/**
|
||||
* Whether to send emails to the test server
|
||||
*/
|
||||
useTestServer: boolean;
|
||||
/**
|
||||
* Email provider config
|
||||
*/
|
||||
provider: EmailProviderConfig;
|
||||
/**
|
||||
* Mail config
|
||||
*/
|
||||
mail: {
|
||||
from: {
|
||||
name: string;
|
||||
address: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export class EmailClient {
|
||||
private config: EmailClientConfig;
|
||||
private cachedTransport?: Transporter;
|
||||
|
||||
constructor(config: EmailClientConfig) {
|
||||
this.config = config;
|
||||
const getTransport = () => {
|
||||
if (transport) {
|
||||
// Reuse the transport if it exists
|
||||
return transport;
|
||||
}
|
||||
|
||||
async sendTemplate<T extends TemplateName>(
|
||||
templateName: T,
|
||||
options: SendEmailOptions<T>,
|
||||
) {
|
||||
if (!process.env.SUPPORT_EMAIL) {
|
||||
console.info("SUPPORT_EMAIL not configured - skipping email send");
|
||||
return;
|
||||
}
|
||||
|
||||
const Template = templates[templateName] as TemplateComponent<T>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const html = render(<Template {...(options.props as any)} />);
|
||||
|
||||
try {
|
||||
await this.sendEmail({
|
||||
from: this.config.mail.from,
|
||||
to: options.to,
|
||||
subject: options.subject,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
html,
|
||||
attachments: options.attachments,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Error sending email", templateName, e);
|
||||
}
|
||||
if (env === "test") {
|
||||
transport = createTransport({ port: 4025 });
|
||||
return transport;
|
||||
}
|
||||
|
||||
async sendEmail(options: Mail.Options) {
|
||||
if (this.config.openPreviews) {
|
||||
await previewEmail(options, {
|
||||
openSimulator: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.transport.sendMail(options);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error("Error sending email", e);
|
||||
}
|
||||
}
|
||||
|
||||
private get transport() {
|
||||
if (this.config.useTestServer) {
|
||||
this.cachedTransport = createTransport({
|
||||
port: 4025,
|
||||
});
|
||||
return this.cachedTransport;
|
||||
}
|
||||
|
||||
if (this.cachedTransport) {
|
||||
// Reuse the transport if it exists
|
||||
return this.cachedTransport;
|
||||
}
|
||||
|
||||
switch (this.config.provider.name) {
|
||||
case "ses": {
|
||||
switch (process.env.EMAIL_PROVIDER) {
|
||||
case "ses":
|
||||
{
|
||||
const ses = new aws.SES({
|
||||
region: process.env["AWS" + "_REGION"],
|
||||
credentialDefaultProvider: defaultProvider,
|
||||
});
|
||||
|
||||
this.cachedTransport = createTransport({
|
||||
transport = createTransport({
|
||||
SES: {
|
||||
ses,
|
||||
aws,
|
||||
|
@ -140,31 +48,78 @@ export class EmailClient {
|
|||
},
|
||||
});
|
||||
}
|
||||
case "smtp": {
|
||||
const hasAuth = process.env.SMTP_USER || process.env.SMTP_PWD;
|
||||
this.cachedTransport = createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: process.env.SMTP_PORT
|
||||
? parseInt(process.env.SMTP_PORT)
|
||||
: undefined,
|
||||
secure: process.env.SMTP_SECURE === "true",
|
||||
auth: hasAuth
|
||||
break;
|
||||
default: {
|
||||
const hasAuth = process.env.SMTP_USER || process.env.SMTP_PWD;
|
||||
transport = createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: process.env.SMTP_PORT
|
||||
? parseInt(process.env.SMTP_PORT)
|
||||
: undefined,
|
||||
secure: process.env.SMTP_SECURE === "true",
|
||||
auth: hasAuth
|
||||
? {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PWD,
|
||||
}
|
||||
: undefined,
|
||||
tls:
|
||||
process.env.SMTP_TLS_ENABLED === "true"
|
||||
? {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PWD,
|
||||
ciphers: "SSLv3",
|
||||
rejectUnauthorized: false,
|
||||
}
|
||||
: undefined,
|
||||
tls:
|
||||
process.env.SMTP_TLS_ENABLED === "true"
|
||||
? {
|
||||
ciphers: "SSLv3",
|
||||
rejectUnauthorized: false,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this.cachedTransport;
|
||||
}
|
||||
}
|
||||
|
||||
return transport;
|
||||
};
|
||||
|
||||
type SendEmailOptions<T extends TemplateName> = {
|
||||
to: string;
|
||||
subject: string;
|
||||
props: TemplateProps<T>;
|
||||
attachments?: Mail.Options["attachments"];
|
||||
};
|
||||
|
||||
export const sendEmail = async <T extends TemplateName>(
|
||||
templateName: T,
|
||||
options: SendEmailOptions<T>,
|
||||
) => {
|
||||
if (!process.env.SUPPORT_EMAIL) {
|
||||
console.info("SUPPORT_EMAIL not configured - skipping email send");
|
||||
return;
|
||||
}
|
||||
|
||||
const Template = templates[templateName] as TemplateComponent<T>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const html = render(<Template {...(options.props as any)} />);
|
||||
|
||||
try {
|
||||
await sendRawEmail({
|
||||
from: {
|
||||
name: "Rallly",
|
||||
address: process.env.NOREPLY_EMAIL || process.env.SUPPORT_EMAIL,
|
||||
},
|
||||
to: options.to,
|
||||
subject: options.subject,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
html,
|
||||
attachments: options.attachments,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Error sending email", templateName, e);
|
||||
}
|
||||
};
|
||||
|
||||
export const sendRawEmail = async (options: Mail.Options) => {
|
||||
const transport = getTransport();
|
||||
try {
|
||||
await transport.sendMail(options);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error("Error sending email", e);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue