docs/ts/develop/integrations/resend.md
Resend provides transactional email with high deliverability and React Email templates. This guide shows how to use it with Encore's Pub/Sub and secrets management.
To get started quickly, create a new app from the example:
$ encore app create --example=ts/resend
Or follow the steps below to add Resend to an existing Encore app.
<Callout type="info">If you haven't installed Encore yet, see the installation guide first.
</Callout>$ npm install resend
If you want to use React Email templates:
$ npm install resend @react-email/components
Before writing code, you'll need to configure a few things in the Resend dashboard:
[email protected] as the from address for testing.See the Resend documentation for more details on domain verification and sending limits.
Store your Resend API key as an Encore secret:
$ encore secret set --type dev,local,pr,production ResendAPIKey
Locally, secrets are stored on your machine and injected when you run encore run. No .env files needed.
-- resend.ts --
import { Resend } from "resend";
import { secret } from "encore.dev/config";
const resendApiKey = secret("ResendAPIKey");
export const resend = new Resend(resendApiKey());
Use the Resend SDK in an Encore API endpoint:
-- send.ts --
import { api } from "encore.dev/api";
import { resend } from "./resend";
interface SendEmailRequest {
to: string;
subject: string;
html: string;
}
interface SendEmailResponse {
id: string;
}
export const sendEmail = api(
{ expose: true, method: "POST", path: "/email/send" },
async (req: SendEmailRequest): Promise<SendEmailResponse> => {
const { data, error } = await resend.emails.send({
from: "Your App <[email protected]>",
to: req.to,
subject: req.subject,
html: req.html,
});
if (error) {
throw new Error(`Failed to send email: ${error.message}`);
}
return { id: data!.id };
}
);
The from address must use a domain you've verified in Resend. For testing, you can use [email protected] which works with any API key.
For better performance, send emails asynchronously using Encore's Pub/Sub. This keeps your API endpoints fast and handles retries automatically:
-- topic.ts --
import { Topic, Subscription } from "encore.dev/pubsub";
import { resend } from "./resend";
interface EmailEvent {
to: string;
subject: string;
html: string;
}
export const emailTopic = new Topic<EmailEvent>("email-send", {
deliveryGuarantee: "at-least-once",
});
const _ = new Subscription(emailTopic, "send-via-resend", {
handler: async (event) => {
const { error } = await resend.emails.send({
from: "Your App <[email protected]>",
to: event.to,
subject: event.subject,
html: event.html,
});
if (error) {
throw new Error(error.message);
}
},
});
Then publish from any endpoint:
import { emailTopic } from "./topic";
// Inside any API endpoint
await emailTopic.publish({
to: "[email protected]",
subject: "Welcome!",
html: "<p>Thanks for signing up.</p>",
});
Locally, Pub/Sub runs in-process so messages are delivered immediately, making it easy to test and debug.
</Callout>When you deploy, Encore automatically provisions and manages the infrastructure your app needs:
Build a Docker image and deploy anywhere:
$ encore build docker my-app:latest
See the self-hosting docs for more details.
Deploy your application to a free staging environment in Encore's development cloud:
$ git push encore main
You can also connect your own AWS or GCP account and Encore will automatically provision Pub/Sub topics, manage secrets, and handle networking in your cloud. See Connect your cloud account for details.