From f7ded6f789c9c1590246eaa7a0e15e286f78bc84 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Wed, 17 Apr 2024 18:42:00 +0800 Subject: [PATCH] Add support for Resend mailer This update expands the mailer support by adding the Resend mailer as an alternative to NodeMailer and Cloudflare Mailer. After setting the environment variable 'MAILER_PROVIDER' to 'resend', users can utilize the Resend HTTP API for mailing. Necessary instructions and variable settings regarding the usage of Resend mailer have also been added to README.md and related modules. --- README.md | 14 +++++- packages/mailers/README.md | 18 +++++++- packages/mailers/src/impl/resend/index.ts | 54 +++++++++++++++++++++++ packages/mailers/src/index.ts | 8 +++- 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 packages/mailers/src/impl/resend/index.ts diff --git a/README.md b/README.md index 8366be0d6..d65b1443c 100644 --- a/README.md +++ b/README.md @@ -339,7 +339,7 @@ This will enable the Edge runtime for your application. ### 2. Using the Cloudflare Mailer -Since the default library `nodemailer` relies on Node.js, we cannot use it in the Edge runtime. Instead, we will use the Cloudflare Mailer. +Since the default library `nodemailer` relies on Node.js, we cannot use it in the Edge runtime. Instead, we will use the Cloudflare Mailer or the Resend Mailer. To use the Cloudflare Mailer, you need to do the following. Set the `MAILER_PROVIDER` environment variable to `cloudflare` in the `apps/web/.env` file: @@ -351,6 +351,18 @@ Setup SPF and DKIM records in your DNS settings. Please follow [the Vercel Email documentation](https://github.com/Sh4yy/vercel-email?tab=readme-ov-file#setup-spf) to set up the SPF and DKIM records. +Alternatively, you can use the Resend Mailer. Set the `MAILER_PROVIDER` environment variable to `resend` in the `apps/web/.env` file: + +``` +MAILER_PROVIDER=resend +``` + +And provide the Resend API key: + +``` +RESEND_API_KEY=your-api-key +``` + ### 3. Installing the Cloudflare CLI Please follow the instructions on the [Cloudflare documentation](https://github.com/cloudflare/next-on-pages/tree/main/packages/next-on-pages#3-deploy-your-application-to-cloudflare-pages) to install the Cloudflare CLI. diff --git a/packages/mailers/README.md b/packages/mailers/README.md index a50e917fd..b57eaea45 100644 --- a/packages/mailers/README.md +++ b/packages/mailers/README.md @@ -25,6 +25,12 @@ To use Cloudflare, please set the environment variable `MAILER_PROVIDER` to `clo MAILER_PROVIDER=cloudflare ``` +To use [Resend](https:///resend.com)'s HTTP API, please set the environment variable `MAILER_PROVIDER` to `resend`. + +``` +MAILER_PROVIDER=resend +``` + ### Send an email ```tsx @@ -42,4 +48,14 @@ async function sendEmail() { } ``` -If you're using the `cloudflare` provider, please also read the instructions of the package [Vercel Email](https://github.com/Sh4yy/vercel-email) to setup your Workers. \ No newline at end of file +## Cloudflare + +If you're using the `cloudflare` provider, please also read the instructions of the package [Vercel Email](https://github.com/Sh4yy/vercel-email) to setup your Workers. + +## Resend + +If you're using the `resend` provider, please add the following environment variables: + +``` +RESEND_API_KEY=your-api-key +``` \ No newline at end of file diff --git a/packages/mailers/src/impl/resend/index.ts b/packages/mailers/src/impl/resend/index.ts new file mode 100644 index 000000000..3dde5ded6 --- /dev/null +++ b/packages/mailers/src/impl/resend/index.ts @@ -0,0 +1,54 @@ +import 'server-only'; + +import { z } from 'zod'; + +import { Mailer } from '../../mailer'; +import { MailerSchema } from '../../schema/mailer.schema'; + +type Config = z.infer; + +const RESEND_API_KEY = z + .string({ + description: 'The API key for the Resend API', + required_error: 'Please provide the API key for the Resend API', + }) + .parse(process.env.RESEND_API_KEY); + +/** + * A class representing a mailer using the Resend HTTP API. + * @implements {Mailer} + */ +export class ResendMailer implements Mailer { + async sendEmail(config: Config) { + const contentObject = + 'text' in config + ? { + text: config.text, + } + : { + html: config.html, + }; + + const res = await fetch('https://api.resend.com/emails', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${RESEND_API_KEY}`, + }, + body: JSON.stringify({ + from: config.from, + to: [config.to], + subject: config.subject, + ...contentObject, + }), + }); + + if (res.ok) { + const data = await res.json(); + + return data; + } + + throw new Error('Failed to send email'); + } +} diff --git a/packages/mailers/src/index.ts b/packages/mailers/src/index.ts index 83027f632..6f0c3f584 100644 --- a/packages/mailers/src/index.ts +++ b/packages/mailers/src/index.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; const MAILER_PROVIDER = z - .enum(['nodemailer', 'cloudflare']) + .enum(['nodemailer', 'cloudflare', 'resend']) .default('nodemailer') .parse(process.env.MAILER_PROVIDER); @@ -26,6 +26,12 @@ export async function getMailer() { return new CloudflareMailer(); } + case 'resend': { + const { ResendMailer } = await import('./impl/resend'); + + return new ResendMailer(); + } + default: throw new Error(`Invalid mailer: ${MAILER_PROVIDER as string}`); }