Back to roadmaps resend Course

Project: Automated Weekly Newsletter Batch Sender

Sending emails one by one in a loop is slow and wastes API bandwidth. Resend provides a Batch API that allows you to deliver up to 100 emails in a single HTTP request payload.


1. Batch API Architecture Flow

graph TD
    A[Fetch 100 Subscribers] --> B[Map to Email Payload Array]
    B --> C[Call resend.batch.send]
    C --> D[Retrieve Delivery IDs]

2. Implementing the Batch Ingestion Code

Let us write a service that queries active subscribers from our database, structures the mailing payload, and uploads them to the Resend batch endpoint:

// src/services/newsletterSender.ts
import { resend } from "../lib/resend";
import { prisma } from "../lib/prisma";

interface Subscriber {
  email: string;
  name: string;
}

export async function sendWeeklyNewsletter() {
  try {
    // 1. Query active newsletter subscribers
    const subscribers = await prisma.user.findMany({
      where: { newsletterSubscribed: true },
      select: { email: true, name: true },
    });

    if (subscribers.length === 0) {
      console.log("No active subscribers to mail.");
      return;
    }

    // 2. Format emails array (maximum 100 items per batch payload)
    const emailPayloads = subscribers.map((sub: Subscriber) => {
      return {
        from: "Newsletter Team <newsletter@mycompany.com>",
        to: [sub.email],
        subject: "Your Weekly SaaS Digest",
        html: `
          <h2>Hello, ${sub.name}!</h2>
          <p>Here is your weekly digest of new features and development strategies.</p>
          <p>Read the full updates on our blog workspace settings page.</p>
        `,
      };
    });

    // 3. Process array in batches of 100
    const batchLimit = 100;
    for (let i = 0; i < emailPayloads.length; i += batchLimit) {
      const batchChunk = emailPayloads.slice(i, i + batchLimit);
      
      console.log(`Sending batch ${i / batchLimit + 1}...`);
      
      const response = await resend.batch.send(batchChunk);

      if (response.error) {
        console.error("Batch delivery failed:", response.error.message);
        continue;
      }

      console.log(`Delivered batch ${i / batchLimit + 1}. Total IDs:`, response.data?.keys.length);
    }

    console.log("Weekly newsletter dispatch complete!");
  } catch (err: any) {
    console.error("Error during newsletter execution:", err.message);
  }
}

3. Rate Limit Considerations

Resend accounts on the starter plan are limited to sending a specific number of emails per second (typically 10 emails/sec). When looping through batch calls, introduce small delays between requests if you have thousands of subscribers to avoid triggering rate limit blockings.

Published on Last updated: