Apidog

All-in-one Collaborative API Development Platform

API Design

API Documentation

API Debugging

API Mocking

API Automated Testing

How to Use Resend API (A Beginners Guide)

Mark Ponomarev

Mark Ponomarev

Updated on April 29, 2025

Email is a critical component of modern web applications, used for everything from user onboarding and notifications to password resets and marketing campaigns. However, building and managing a reliable email sending infrastructure can be complex and time-consuming. This is where email API services like Resend come in.

Resend offers a developer-friendly platform designed to simplify the process of sending transactional and marketing emails. It provides robust APIs, detailed analytics, and excellent deliverability, allowing developers to focus on building their applications rather than worrying about email infrastructure.

This comprehensive guide will walk you through everything you need to know to get started with the Resend API, from understanding its core concepts and pricing to integrating it with various popular frameworks and platforms.

💡
Want a great API Testing tool that generates beautiful API Documentation?

Want an integrated, All-in-One platform for your Developer Team to work together with maximum productivity?

Apidog delivers all your demans, and replaces Postman at a much more affordable price!
button

What is Resend?

Resend is an email API platform built for developers. It aims to provide a superior developer experience compared to older email service providers (ESPs). Key features include:

  • Modern API: A clean, RESTful API that's easy to integrate into any application.
  • High Deliverability: Focuses on ensuring your emails reach the inbox, not the spam folder, through features like custom domain verification (DKIM, SPF, DMARC), dedicated IPs (as an add-on), and automatic suppression list management.
  • Framework Integrations: Offers official SDKs and guides for popular frameworks like Node.js, Next.js, Python, Ruby, PHP, Go, and more.
  • React Email Integration: Seamlessly integrates with React Email, allowing you to build beautiful, responsive email templates using React components.
  • Webhooks: Provides real-time notifications about email events like delivery, bounces, opens, clicks, and spam complaints.
  • Detailed Analytics: Offers insights into email performance through a user-friendly dashboard.
  • Developer Focus: Designed with developers in mind, offering clear documentation, helpful SDKs, and tools like test emails for easier development and debugging.

Resend positions itself as a more modern, developer-centric alternative to established players like SendGrid, Mailgun, or AWS SES, focusing on ease of use, reliability, and integrating well with modern web development workflows.

What's Resend Pricing?

Resend offers a tiered pricing structure based on the number of emails sent per month, with separate considerations for transactional and marketing emails (though the pricing page primarily details transactional plans).

Here's a breakdown of their transactional email plans (as of the time of writing):

Free Plan:

  • Cost: $0 / month
  • Emails: Up to 3,000 emails per month
  • Daily Limit: 100 emails per day
  • Domains: 1 custom domain
  • Data Retention: 1 day
  • Support: Ticket Support
  • Key Features: RESTful API, SMTP Relay, SDKs, Open/Link Tracking, React Email Integration, Automatic Suppression List, DKIM/SPF/DMARC Authentication, 1 Webhook Endpoint.
  • Limitations: No Single Sign-On (SSO), No Dedicated IPs, Limited domains and daily sending.

Pro Plan:

  • Cost: $20 / month
  • Emails: Up to 50,000 emails per month (with overage charges applying beyond this)
  • Daily Limit: No daily limit
  • Domains: 10 custom domains
  • Data Retention: 3 days
  • Support: Ticket Support
  • Key Features: All Free plan features, plus SSO, 10 Webhook Endpoints.
  • Limitations: No Dedicated IPs included (available as add-on later), No Slack support.

Scale Plan:

  • Cost: $90 / month
  • Emails: Up to 100,000 emails per month (with overage charges)
  • Daily Limit: No daily limit
  • Domains: 1,000 custom domains
  • Data Retention: 7 days
  • Support: Slack & Ticket Support
  • Key Features: All Pro plan features, plus Dedicated IP available as an add-on ($30/mo, requires >500 emails/day).
  • Limitations: Dedicated IPs are an add-on.

Enterprise Plan:

  • Cost: Custom pricing
  • Emails: Custom volume
  • Daily Limit: No daily limit
  • Domains: Flexible
  • Data Retention: Flexible
  • Support: Priority Support, Urgent Response SLA, Deliverability Expertise
  • Key Features: All Scale plan features, plus Dedicated IP Warming, Deliverability Insights, Flexible Webhooks, SSO included.

Key Considerations:

  • Overage: Sending more emails than your plan allows will incur additional costs per email.
  • Dedicated IPs: Available as an add-on for the Scale and Enterprise plans for an additional monthly fee, recommended for high-volume senders concerned about shared IP reputation.
  • Data Retention: The duration for which Resend stores logs and details about your sent emails varies by plan.
  • Marketing Emails: The pricing page has a toggle for Marketing Emails, suggesting different plans or pricing structures might apply, but details were focused on transactional emails in the scraped content. Check the Resend website for the most current Marketing Email pricing.

The Free plan is generous enough for small projects or testing purposes. The Pro and Scale plans cater to growing applications with increasing email volumes and feature requirements. The Enterprise plan provides tailored solutions for large-scale operations.

Getting Started with Resend

Before you can send emails, you need to set up your Resend account and configure your sending domain.

1. Sign Up and Create an API Key

  • Go to the Resend website and sign up for an account.
  • Navigate to the API Keys section in your Resend dashboard (https://resend.com/api-keys).
  • Click Create API Key.
  • Give your API key a descriptive name (e.g., my-app-key).
  • Choose the permission level:
  • Full access: Allows all API actions (create, delete, get, update resources). Use with caution, typically only needed for backend management tasks.
  • Sending access: Only allows sending emails. This is the recommended permission for your application's sending logic. You can optionally restrict this key to send only from a specific verified domain.
  • Click Create.
  • Important: Resend will show you the API key only once. Copy it immediately and store it securely (e.g., in an environment variable, secrets manager). Do not commit it directly into your codebase.

2. Verify Your Domain

To send emails that appear professional and avoid spam filters, you must verify a domain you own. Sending from unverified domains or default addresses like onboarding@resend.dev is only suitable for initial testing.

  • Go to the Domains section in your Resend dashboard (https://resend.com/domains).
  • Click Add Domain and enter the domain you want to send emails from (e.g., yourcompany.com).
  • Choose your DNS provider from the list or select 'Other'.
  • Resend will provide you with DNS records (usually MX, TXT for SPF, and CNAME/TXT for DKIM) that you need to add to your domain's DNS settings.
  • SPF (Sender Policy Framework): Specifies which mail servers are authorized to send email on behalf of your domain.
  • DKIM (DomainKeys Identified Mail): Adds a digital signature to emails, allowing receiving servers to verify the email hasn't been tampered with and originated from an authorized server.
  • Log in to your domain registrar or DNS provider (e.g., GoDaddy, Cloudflare, Namecheap) and add the records provided by Resend.
  • DNS changes can take some time to propagate (minutes to hours, sometimes up to 48 hours).
  • Once the records are added, go back to the Resend Domains dashboard and click the Verify button next to your domain. Resend will check if the DNS records are set up correctly. Once verified, the status will update, and you can start sending emails from addresses associated with that domain (e.g., support@yourcompany.com, noreply@yourcompany.com).

3. Sending Test Emails

During development, it's crucial to test email sending without affecting your domain's reputation or sending to real users accidentally. Resend provides special email addresses for testing different scenarios:

  • Test Delivered: Send to delivered@resend.dev. This simulates a successfully delivered email.
  • Test Bounced: Send to bounced@resend.dev. This simulates a hard bounce (e.g., the recipient address doesn't exist), triggering a bounce event.
  • Test Marked as Spam: Send to complained@resend.dev. This simulates a recipient marking your email as spam, triggering a complaint event.

Using these test addresses allows you to verify your integration and test webhook handlers for bounce and complaint events safely.

Integrating Resend with Frameworks

Resend provides official SDKs and straightforward integration methods for various languages and frameworks. We'll cover some popular examples based on the provided documentation. The core concept usually involves:

  1. Installing the Resend SDK (if available) or using standard HTTP requests.
  2. Initializing the Resend client with your API key (loaded securely, usually from environment variables).
  3. Calling the emails.send method (or equivalent) with parameters like from, to, subject, and html or react.

Sending with Next.js

Next.js is a popular React framework. Resend integrates nicely, especially with React Email.

1. Install:

npm install resend
# or
yarn add resend
# or
pnpm add resend

2. Create Email Template (Optional but recommended):Use React Email or create a simple React component for your email body.

// components/email-template.tsx
import * as React from 'react';

interface EmailTemplateProps {
  firstName: string;
}

export const EmailTemplate: React.FC<Readonly<EmailTemplateProps>> = ({
  firstName,
}) => (
  <div>
    <h1>Welcome, {firstName}!</h1>
  </div>
);

3. Create API Route:Create an API route handler to send the email.

  • App Router: app/api/send/route.ts
  • Pages Router: pages/api/send.ts
// app/api/send/route.ts (App Router Example)
import { EmailTemplate } from '../../../components/email-template'; // Adjust path if needed
import { Resend } from 'resend';

// Ensure RESEND_API_KEY is set in your .env.local
const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST() {
  try {
    const { data, error } = await resend.emails.send({
      from: 'Your Name <you@yourverifieddomain.com>', // Use your verified domain
      to: ['delivered@resend.dev'], // Replace with recipient or test address
      subject: 'Hello from Resend and Next.js!',
      react: EmailTemplate({ firstName: 'Test' }), // Pass props to your template
      // Alternatively, use `html`:
      // html: '<strong>It works!</strong>'
    });

    if (error) {
      return Response.json({ error }, { status: 400 });
    }

    return Response.json(data);
  } catch (error) {
    return Response.json({ error }, { status: 500 });
  }
}

// pages/api/send.ts (Pages Router Example - adapt imports/response)
// import type { NextApiRequest, NextApiResponse } from 'next';
// import { EmailTemplate } from '../../components/EmailTemplate';
// import { Resend } from 'resend';
//
// const resend = new Resend(process.env.RESEND_API_KEY);
//
// export default async (req: NextApiRequest, res: NextApiResponse) => {
//   try { // Added try...catch for better error handling
//     const { data, error } = await resend.emails.send({
//       from: 'Your Name <you@yourverifieddomain.com>',
//       to: ['delivered@resend.dev'],
//       subject: 'Hello world',
//       react: EmailTemplate({ firstName: 'John' }),
//     });
//
//     if (error) {
//       return res.status(400).json(error);
//     }
//
//     res.status(200).json(data);
//   } catch (e) {
//      res.status(500).json({ error: 'Internal Server Error' });
//   }
// };

4. Trigger:Call this API endpoint from your frontend (e.g., after a form submission) using fetch or a library like axios. Remember to replace placeholder values with your actual verified domain and recipient lists.

Sending with Astro

Astro is a modern static site builder that also supports server-side rendering (SSR).

1. Install Resend:

npm install resend
# or
yarn add resend
# or
pnpm add resend

2. Install SSR Adapter:Astro needs an SSR adapter to run server-side code on demand. Install one suitable for your deployment target (e.g., @astrojs/node, @astrojs/vercel, @astrojs/cloudflare).

npx astro add node # Example for Node.js adapter

Follow the adapter's setup instructions in your astro.config.mjs.

3. Add API Key:Store your RESEND_API_KEY in your .env file.

4. Create Astro Action:Use Astro Actions (experimental feature as of writing, check Astro docs for current status) or standard API endpoints.

// src/actions/index.ts (Using Astro Actions)
import { ActionError, defineAction, z } from 'astro:actions';
import { Resend } from 'resend';

// Ensure RESEND_API_KEY is available via import.meta.env
const resend = new Resend(import.meta.env.RESEND_API_KEY);

export const server = {
  send: defineAction({
    // Example: Define input validation if needed
    // input: z.object({ email: z.string().email() }),
    handler: async (/* { email } - if using input */) => {
      try { // Added try...catch
        const { data, error } = await resend.emails.send({
          from: 'Your Name <you@yourverifieddomain.com>',
          to: ['delivered@resend.dev'], // Replace with recipient
          subject: 'Hello from Resend and Astro!',
          html: '<strong>Astro works!</strong>',
          // You can also use React templates if you set up React in Astro
          // react: <YourAstroCompatibleReactEmail firstName="Astro" />
        });

        if (error) {
          console.error("Resend Error:", error); // Log error
          // Throwing ActionError helps Astro handle errors gracefully
          throw new ActionError({
            code: 'BAD_REQUEST', // Or be more specific based on error
            message: error.message || 'Failed to send email',
          });
        }

        return data; // Return success data
      } catch (e) {
         console.error("Handler Error:", e);
         // Re-throw or throw a new ActionError
         throw new ActionError({
             code: 'INTERNAL_SERVER_ERROR',
             message: 'An unexpected error occurred.',
         });
      }
    },
  }),
};

// Alternative: API Endpoint (e.g., src/pages/api/send.ts)
// import type { APIRoute } from 'astro';
// import { Resend } from 'resend';
//
// const resend = new Resend(import.meta.env.RESEND_API_KEY);
//
// export const POST: APIRoute = async ({ request }) => {
//   // const body = await request.json(); // If data comes from request body
//   try {
//     const { data, error } = await resend.emails.send({ /* ... email params ... */ });
//     if (error) {
//       return new Response(JSON.stringify(error), { status: 400 });
//     }
//     return new Response(JSON.stringify(data), { status: 200 });
//   } catch (e) {
//     return new Response(JSON.stringify({ message: "Server Error"}), { status: 500 });
//   }
// }

5. Trigger:Call the action or endpoint from your Astro components or pages, typically within a form submission handler.

Sending with Bun

Bun is a fast JavaScript runtime with a built-in bundler, transpiler, task runner, and npm client.

1. Install:

bun install resend

2. Create Email Template (Optional):Similar to Next.js, you can create a .tsx file for your React email template.

// email-template.tsx
import * as React from 'react';

interface EmailTemplateProps {
  firstName: string;
}

export const EmailTemplate: React.FC<Readonly<EmailTemplateProps>> = ({
  firstName,
}) => (
  <div>
    <h1>Welcome, {firstName}!</h1>
  </div>
);

3. Create Bun Server Script:Create a script (e.g., index.tsx) to run a simple HTTP server using Bun.

// index.tsx
import { Resend } from 'resend';
import { EmailTemplate } from './email-template'; // Assuming it's in the same dir

// Load API key from environment variables
const resendApiKey = process.env.RESEND_API_KEY;
if (!resendApiKey) {
  console.error("Error: RESEND_API_KEY environment variable not set.");
  process.exit(1); // Exit if key is missing
}
const resend = new Resend(resendApiKey);

const server = Bun.serve({
  port: 3000,
  async fetch(req) { // Added 'req' argument
    // Optional: Check request method, path, etc.
    // if (new URL(req.url).pathname !== '/send') {
    //   return new Response("Not Found", { status: 404 });
    // }
    // if (req.method !== 'POST') {
    //    return new Response("Method Not Allowed", { status: 405 });
    // }

    try {
      const { data, error } = await resend.emails.send({
        from: 'Your Name <you@yourverifieddomain.com>',
        to: ['delivered@resend.dev'],
        subject: 'Hello from Resend and Bun!',
        react: EmailTemplate({ firstName: 'Bun User' }),
        // Or use html: '<strong>Bun works!</strong>'
      });

      if (error) {
        console.error("Resend Error:", error);
        // Return a proper JSON error response
        return new Response(JSON.stringify({ error: error.message || 'Failed to send email' }), {
          status: 500, // Or 400 depending on error type
          headers: { 'Content-Type': 'application/json' },
        });
      }

      // Return success response
      return new Response(JSON.stringify(data), {
        status: 200,
        headers: { 'Content-Type': 'application/json' },
      });

    } catch (e) {
        console.error("Server Error:", e);
        return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
          status: 500,
          headers: { 'Content-Type': 'application/json' },
        });
    }
  },
  error(error) { // Added basic error handler for the server itself
      return new Response(`<pre>${error}\\\\\\\\n${error.stack}</pre>`, {
          headers: { "Content-Type": "text/html" },
      });
  },
});

console.log(`Listening on <http://localhost>:${server.port} ...`);

4. Run:Start the server using RESEND_API_KEY=your_api_key bun run index.tsx. Accessing http://localhost:3000 (or triggering the specific route/method you defined) will send the email.

Sending with Nuxt

Nuxt is a popular Vue.js framework.

1. Install:

npm install resend
# or
yarn add resend
# or
pnpm add resend

2. Create Server Route:Nuxt uses a server/ directory for backend logic. Create a file like server/api/send.post.ts (the .post indicates it handles POST requests).

// server/api/send.post.ts
import { Resend } from 'resend';

// Access API Key securely (e.g., via runtimeConfig in nuxt.config.ts)
// See: <https://nuxt.com/docs/guide/going-further/runtime-config>
const config = useRuntimeConfig();
const resend = new Resend(config.resendApiKey); // Assuming key is set in runtime config

export default defineEventHandler(async (event) => {
  // Optional: Read body if data comes from request
  // const body = await readBody(event);

  try {
    const data = await resend.emails.send({
      from: 'Your Name <you@yourverifieddomain.com>',
      to: ['delivered@resend.dev'],
      subject: 'Hello from Resend and Nuxt!',
      html: '<strong>Nuxt works!</strong>',
      // You can integrate Vue email templates (e.g., using vue-email)
      // See: <https://github.com/Dave136/vue-email>
    });

    // Nuxt 3 automatically handles returning the data as JSON
    return data;

  } catch (error: any) { // Catch specific error types if possible
    console.error("Resend Error:", error);
    // Throw an error that Nuxt can handle, setting the status code
    throw createError({
        statusCode: 400, // Or 500
        statusMessage: 'Failed to send email',
        data: error // Optionally include error details
    });
  }
});

// In your nuxt.config.ts, define runtimeConfig:
// export default defineNuxtConfig({
//   runtimeConfig: {
//     resendApiKey: process.env.NUXT_RESEND_API_KEY, // Server-side only
//     public: {
//       // Public keys accessible on client-side
//     }
//   }
// })
// And set NUXT_RESEND_API_KEY in your .env

3. Trigger:Call the /api/send endpoint (using POST method) from your Nuxt pages or components using $fetch or useFetch.

Sending with Vercel Functions

Vercel Functions are serverless functions that integrate seamlessly with Next.js or can be used standalone. The Next.js example above already demonstrates usage within a Vercel environment. If using Vercel Functions without Next.js (e.g., with a static site generator or another framework deployed on Vercel), the approach is similar:

1. Create Function:Create a file in the api/ directory of your project (e.g., api/send.ts).

// api/send.ts (Example for standard Vercel Function)
import type { VercelRequest, VercelResponse } from '@vercel/node';
import { Resend } from 'resend'; // You might need to install resend

// Ensure RESEND_API_KEY is set as a Vercel Environment Variable
const resendApiKey = process.env.RESEND_API_KEY;

if (!resendApiKey) {
  console.error("RESEND_API_KEY is not set");
  // Don't proceed if the key is missing in production
}

const resend = new Resend(resendApiKey);

export default async function handler(
  request: VercelRequest,
  response: VercelResponse,
) {
  // Recommended: Check for POST method
  if (request.method !== 'POST') {
    return response.status(405).json({ message: 'Method Not Allowed' });
  }

  try {
    const { data, error } = await resend.emails.send({
      from: 'Your Name <you@yourverifieddomain.com>',
      to: ['delivered@resend.dev'],
      subject: 'Hello from Resend & Vercel Functions!',
      html: '<strong>It works on Vercel!</strong>',
      // React templates can be used if your function bundles React
    });

    if (error) {
      console.error('Resend Error:', error);
      return response.status(400).json(error);
    }

    return response.status(200).json(data);

  } catch (e) {
    console.error('Handler Error:', e);
    return response.status(500).json({ message: 'Internal Server Error' });
  }
}

2. Configure Environment Variable:Add your RESEND_API_KEY as an Environment Variable in your Vercel project settings.

3. Deploy:Deploy your project using the Vercel CLI (vercel) or Git integration.

4. Trigger:Make a POST request to the deployed function URL (e.g., https://your-project.vercel.app/api/send).

Sending with Supabase Edge Functions

Supabase Edge Functions run on Deno Deploy, close to your users. They use Deno and standard Web APIs like fetch. Resend doesn't have an official Deno SDK yet, so you use fetch directly.

1. Create Supabase Function:Use the Supabase CLI:

supabase functions new resend-email-sender # Choose a name
cd supabase/functions/resend-email-sender

2. Edit Handler:Modify the generated index.ts file.

// supabase/functions/resend-email-sender/index.ts
import { serve } from "<https://deno.land/std@0.177.0/http/server.ts>"; // Use appropriate std version

// Access API Key securely via Supabase Edge Function environment variables
const RESEND_API_KEY = Deno.env.get('RESEND_API_KEY');

// Basic request handler
const handler = async (_request: Request): Promise<Response> => {
  if (!RESEND_API_KEY) {
      console.error("RESEND_API_KEY environment variable not set.");
      return new Response(JSON.stringify({ error: "Server configuration error" }), {
          status: 500, headers: { 'Content-Type': 'application/json' }
      });
  }

  // Optional: Check _request method, headers, or body if needed

  try {
    const res = await fetch('<https://api.resend.com/emails>', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${RESEND_API_KEY}` // Use the key here
        },
        body: JSON.stringify({
            from: 'Your Name <you@yourverifieddomain.com>',
            to: ['delivered@resend.dev'], // Replace recipient
            subject: 'Hello from Resend & Supabase Edge!',
            html: '<strong>It works! Edge Functions are cool.</strong>',
            // Note: Sending React components directly isn't feasible here
            // without a build step in the edge function to render them to HTML.
            // Send pre-rendered HTML or plain text.
        })
    });

    // Handle potential non-OK responses from Resend API
    if (!res.ok) {
        const errorData = await res.json().catch(() => ({ message: 'Failed to parse Resend error response' }));
        console.error("Resend API Error:", res.status, errorData);
        return new Response(JSON.stringify({ error: 'Failed to send email via Resend', details: errorData }), {
            status: res.status, // Forward Resend's status code
            headers: { 'Content-Type': 'application/json' },
        });
    }

    // Parse successful response
    const data = await res.json();

    // Return success response
    return new Response(JSON.stringify(data), {
        status: 200,
        headers: { 'Content-Type': 'application/json' },
    });

  } catch (error) {
      console.error("Edge Function Error:", error);
      return new Response(JSON.stringify({ error: 'Internal Server Error in Edge Function' }), {
          status: 500,
          headers: { 'Content-Type': 'application/json' },
      });
  }
};

// Start the server
serve(handler);
console.log("Supabase Edge Function 'resend-email-sender' is running...");

3. Set Environment Variable:Set the RESEND_API_KEY locally using supabase secrets set RESEND_API_KEY your_actual_key and also set it in your Supabase project's Function settings for deployment.

4. Deploy & Invoke:

# Test locally (optional)
supabase functions serve resend-email-sender --no-verify-jwt

# Deploy
supabase functions deploy resend-email-sender --no-verify-jwt

Invoke the function using its URL, typically via a Supabase client library call from your frontend or another backend service.

Sending with Cloudflare Workers

Cloudflare Workers are serverless functions running on Cloudflare's edge network. Resend's Node.js SDK can often work in Workers environments with appropriate bundling.

1. Setup Worker Project:Initialize a Worker project, often using npm create cloudflare. Ensure it's set up for modules and bundling (e.g., using Wrangler with Webpack or esbuild).

2. Install Resend:

npm install resend
# or yarn/pnpm

3. Create Email Template (Optional):If using React, create your template file (.tsx).

4. Edit Worker Script:Modify your main worker file (e.g., src/index.ts or src/index.tsx if using React).

// src/index.tsx (Example using React)
import { Resend } from 'resend';
// Assuming you have a React template component
import { EmailTemplate } from './emails/email-template'; // Adjust path

// Define the expected environment variables for type safety
export interface Env {
  RESEND_API_KEY: string;
}

export default {
  async fetch(
    request: Request,
    env: Env, // Access environment variables via 'env'
    ctx: ExecutionContext
  ): Promise<Response> {

    // Instantiate Resend using the API key from environment variables
    const resend = new Resend(env.RESEND_API_KEY);

    // Optional: Check request method, URL path, etc.
    // Example: Only allow POST requests to a specific path
    // const url = new URL(request.url);
    // if (url.pathname !== '/send-email' || request.method !== 'POST') {
    //   return new Response('Not Found or Method Not Allowed', { status: 404 });
    // }

    try {
      const { data, error } = await resend.emails.send({
        from: 'Your Name <you@yourverifieddomain.com>',
        to: ['delivered@resend.dev'], // Replace recipient
        subject: 'Hello from Resend & Cloudflare Workers!',
        // Use the React component if applicable
        react: <EmailTemplate firstName="Worker User" />,
        // Or use HTML
        // html: '<strong>It works from the Edge!</strong>',
      });

      if (error) {
        console.error("Resend Error:", JSON.stringify(error));
        return Response.json({ error: 'Failed to send email via Resend' }, { status: 400 });
      }

      return Response.json(data);

    } catch (e) {
      console.error("Worker Error:", e);
      // Log the error stack if possible
      if (e instanceof Error) {
         console.error(e.stack);
      }
      return Response.json({ error: 'Internal Server Error in Worker' }, { status: 500 });
    }
  },
} // satisfies ExportedHandler<Env>; // Optional: Use satisfies for better type checking

5. Configure Environment Variable:Set your RESEND_API_KEY as a secret for your Worker using Wrangler:

npx wrangler secret put RESEND_API_KEY
# Paste your key when prompted

6. Deploy:

npx wrangler deploy # Or 'wrangler dev' for local testing

Invoke the Worker using its assigned URL.

Sending with AWS Lambda

Scraping for the AWS Lambda documentation page timed out, so this section is based on general principles.

Sending emails from AWS Lambda using Resend follows a similar pattern:

1. Setup Lambda Function:Create a Lambda function using your preferred runtime (Node.js is common and works well with the Resend SDK). Ensure your Lambda has internet access (e.g., configured within a VPC with a NAT Gateway or using default VPC settings that allow egress).

2. Install Resend SDK:Include resend in your function's deployment package (e.g., in package.json and run npm install before zipping or use Lambda Layers).

3. Store API Key Securely:Use AWS Secrets Manager or AWS Systems Manager Parameter Store to store your RESEND_API_KEY. Grant your Lambda function's execution role permission to read this secret. Do not hardcode the key in the Lambda function code.

4. Write Lambda Handler Code (Node.js Example):

// lambda_function.js (Node.js example)
const { Resend } = require('resend');
// AWS SDK clients (if getting key from Secrets Manager/Parameter Store)
const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager"); // V3 SDK

let resend; // Initialize outside handler for potential reuse

async function getApiKey() {
    // Replace with your secret name/ARN and region
    const secretName = "your/resend/api/key/secret";
    const client = new SecretsManagerClient({ region: "your-region" });
    try {
        const command = new GetSecretValueCommand({ SecretId: secretName });
        const response = await client.send(command);
        if ('SecretString' in response) {
            // Assuming the secret stores the key directly or as JSON like {"apiKey": "re_..."}
            const secret = JSON.parse(response.SecretString);
            return secret.apiKey; // Adjust parsing based on how you stored it
        }
        throw new Error("API Key not found in secret string");
    } catch (error) {
        console.error("Error retrieving API Key from Secrets Manager:", error);
        throw error; // Re-throw to signal failure
    }
}

exports.handler = async (event, context) => {
    // Optional: Parse event data if needed (e.g., from API Gateway trigger)
    // const body = JSON.parse(event.body || '{}');
    // const recipient = body.to;

    try {
        if (!resend) {
            const apiKey = await getApiKey();
            if (!apiKey) {
                return { statusCode: 500, body: JSON.stringify({ message: "API Key configuration error" }) };
            }
            resend = new Resend(apiKey);
        }

        const { data, error } = await resend.emails.send({
            from: 'Your Name <you@yourverifieddomain.com>',
            to: ['delivered@resend.dev'], // Use recipient from event or fixed value
            subject: 'Hello from Resend & AWS Lambda!',
            html: '<strong>Lambda email sent successfully!</strong>',
            // React requires a build step or server-side rendering setup within Lambda
        });

        if (error) {
            console.error('Resend Error:', error);
            return {
                statusCode: 400, // Or appropriate status based on error
                body: JSON.stringify(error),
            };
        }

        return {
            statusCode: 200,
            body: JSON.stringify(data),
             headers: { 'Content-Type': 'application/json' },
        };

    } catch (e) {
        console.error('Lambda Handler Error:', e);
        return {
            statusCode: 500,
            body: JSON.stringify({ message: 'Internal Server Error' }),
        };
    }
};

5. Configure Trigger:Set up a trigger for your Lambda function (e.g., API Gateway for HTTP requests, SQS queue, EventBridge event).

6. Deploy:Deploy your Lambda function and its dependencies.

Using React Email with Resend

A major advantage of Resend is its seamless integration with React Email. React Email allows you to build beautiful, responsive email templates using standard React components and syntax.

Benefits:

  • Component-Based: Structure emails like web apps using reusable components.
  • Type Safety: Use TypeScript for more robust templates.
  • Local Development: Develop and preview emails locally in your browser.
  • No Complex Templating Languages: Avoid proprietary or complex email templating syntax.

Setup (Based on React Email Docs - may vary slightly):

Install: Add react-email and its core components to your project. You'll likely need resend as well if sending through them.

npm install react-email @react-email/components resend
# or yarn/pnpm

Create Email Templates: Create .tsx files for your emails, usually in a dedicated emails/ directory.

// emails/welcome.tsx
import { Html, Button, Text } from '@react-email/components';
import * as React from 'react';

interface WelcomeEmailProps {
  name: string;
  signupLink: string;
}

export const WelcomeEmail: React.FC<Readonly<WelcomeEmailProps>> = ({ name, signupLink }) => (
  <Html>
    <Text>Hello {name},</Text>
    <Text>Welcome aboard! Click the button below to get started.</Text>
    <Button href={signupLink}>Complete Signup</Button>
  </Html>
);

export default WelcomeEmail; // Default export is often helpful

Integrate with Sending Logic: In your backend API route or serverless function, import the email component and pass it to Resend's react option.

// Example in a Next.js API Route (app/api/send-welcome/route.ts)
import { Resend } from 'resend';
import WelcomeEmail from '../../../emails/welcome'; // Adjust path

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(request: Request) {
  try {
    const body = await request.json(); // Assuming { email: '...', name: '...' } in body
    const signupUrl = "<https://yoursite.com/signup-step2>"; // Example URL

    const { data, error } = await resend.emails.send({
      from: 'Your App <welcome@yourverifieddomain.com>',
      to: [body.email],
      subject: 'Welcome to Our Platform!',
      // Pass the React component directly
      react: WelcomeEmail({ name: body.name, signupLink: signupUrl }),
    });

    if (error) {
      return Response.json({ error }, { status: 400 });
    }
    return Response.json(data);
  } catch (error) {
    return Response.json({ error }, { status: 500 });
  }
}

Resend (and React Email's build process if used standalone) handles rendering the React component to email-safe HTML behind the scenes. This significantly improves the developer experience for creating and maintaining email templates.

Conclusion

Resend offers a modern, developer-focused solution for sending emails. Its clean API, excellent framework integrations (especially with React Email), focus on deliverability, and helpful features like test emails and webhooks make it a compelling choice for applications of all sizes.

By following the steps outlined in this guide—setting up your account, verifying your domain, choosing the right integration method for your framework, and leveraging tools like React Email—you can quickly and reliably integrate robust email functionality into your projects. Remember to always handle API keys securely and monitor your sending activity through the Resend dashboard and webhooks to ensure optimal deliverability and user experience.

💡
Want a great API Testing tool that generates beautiful API Documentation?

Want an integrated, All-in-One platform for your Developer Team to work together with maximum productivity?

Apidog delivers all your demans, and replaces Postman at a much more affordable price!
button
Crawl4AI Tutorial: A Beginner's GuideViewpoint

Crawl4AI Tutorial: A Beginner's Guide

In the age of AI, accessing and processing web data efficiently is crucial. Crawl4AI emerges as a powerful, open-source web crawler and scraper meticulously engineered for developers working with Large Language Models (LLMs), AI agents, and modern data pipelines. This tutorial provides a deep dive into Crawl4AI, covering everything from installation to advanced crawling techniques. 💡Want a great API Testing tool that generates beautiful API Documentation? Want an integrated, All-in-One platfo

Mark Ponomarev

April 30, 2025

How to Run Qwen 3 Locally with Ollama & VLLMViewpoint

How to Run Qwen 3 Locally with Ollama & VLLM

The landscape of large language models (LLMs) is evolving at breakneck speed. Models are becoming more powerful, capable, and, importantly, more accessible. The Qwen team recently unveiled Qwen3, their latest generation of LLMs, boasting impressive performance across various benchmarks, including coding, math, and general reasoning. With flagship models like the Mixture-of-Experts (MoE) Qwen3-235B-A22B rivaling established giants and even smaller dense models like Qwen3-4B competing with previou

Ashley Innocent

April 29, 2025

How to Use Deepseek V3 with Cursor for FreeViewpoint

How to Use Deepseek V3 with Cursor for Free

Learn to use Deepseek V3 for FREE with Cursor in this step-by-step beginner's guide! Code a Python factorial function with AI. My takes: fast and cost-effective!

Ashley Goolam

April 29, 2025