ANTIGRAVITY LABJP
Articles/Integrations
Integrations/2026-03-26Intermediate

Antigravity × Resend + React Email: Automate Transactional Emails — Build Beautiful Templates with AI Assistance

Learn how to build type-safe, beautifully designed transactional emails using Antigravity IDE with Resend and React Email. Includes welcome, payment confirmation, and password reset implementation examples.

antigravity429resendreact-emailemail-automationtypescript26next.js4integrations20

Setup and context

Transactional emails — welcome messages, payment confirmations, password resets — are a critical part of any web application. Yet building HTML emails remains one of the most frustrating tasks in web development, thanks to inconsistent rendering across email clients and the need for table-based layouts.

In this guide, we'll combine Antigravity IDE's AI-powered development features with Resend (a developer-first email API) and React Email (a component library for building emails with React) to create a type-safe, maintainable email delivery system.

By leveraging Antigravity's agent capabilities, you can generate email templates, implement API routes, and test delivery — all within a streamlined AI-assisted workflow.

What Are Resend and React Email?

Resend

Resend is a modern email delivery API built for developers. Compared to legacy services like SendGrid or Mailgun, it offers several advantages:

  • Simple API: Send emails instantly via REST API or official SDKs (Node.js, Python, Go, Ruby)
  • React Email integration: Write templates in JSX and send them directly
  • High deliverability: Automatic SPF, DKIM, and DMARC configuration
  • Real-time analytics: Track open rates, click rates, and bounces from the dashboard

React Email

React Email lets you build email templates using React components. It abstracts away the quirks of HTML email — table layouts, client-specific hacks, and inline styles — behind a clean component API.

// Basic React Email component example
import { Html, Head, Body, Container, Text } from "@react-email/components";
 
// Each component generates email-client-compatible HTML
// <Container> → centered <table> layout
// <Text> → Outlook-compatible <p> tags

Setting Up Your Environment

Prerequisites

  • Node.js 20 or later
  • Antigravity IDE (latest version)
  • Resend account (free tier: 3,000 emails/month)
  • Next.js project (App Router recommended)

Installing Packages

Open the Antigravity terminal and run:

# Install Resend SDK and React Email components
npm install resend @react-email/components
 
# Install the dev preview server
npm install -D react-email
 
# Expected output:
# added 42 packages in 8s

Environment Variables

Add your Resend API key to .env.local in your project root:

# .env.local
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tip: Use Antigravity's inline chat (Cmd+I) and type "Add a Resend API key entry to .env.local" — the agent will add it in the correct format automatically.

Building Email Templates

Directory Structure

src/
├── emails/                  # Email templates
│   ├── welcome.tsx          # Welcome email
│   ├── payment-confirm.tsx  # Payment confirmation
│   └── password-reset.tsx   # Password reset
├── lib/
│   └── email.ts             # Resend client setup
└── app/
    └── api/
        └── send-email/
            └── route.ts     # Email sending API

Welcome Email Template

Ask Antigravity's agent to "Create a welcome email template using React Email," and it will generate something like this:

// src/emails/welcome.tsx
import {
  Html,
  Head,
  Preview,
  Body,
  Container,
  Section,
  Text,
  Button,
  Img,
  Hr,
} from "@react-email/components";
 
interface WelcomeEmailProps {
  userName: string;
  loginUrl: string;
}
 
export default function WelcomeEmail({
  userName = "User",
  loginUrl = "https://example.com/login",
}: WelcomeEmailProps) {
  return (
    <Html lang="en">
      <Head />
      {/* Preview text shown next to the subject line in inboxes */}
      <Preview>Welcome aboard, {userName}!</Preview>
      <Body style={main}>
        <Container style={container}>
          <Img
            src="https://example.com/logo.png"
            width={48}
            height={48}
            alt="Logo"
          />
          <Text style={heading}>Welcome, {userName}!</Text>
          <Text style={paragraph}>
            Your account has been created successfully. Log in now
            to explore all the features available to you.
          </Text>
          <Section style={buttonContainer}>
            <Button style={button} href={loginUrl}>
              Log In
            </Button>
          </Section>
          <Hr style={hr} />
          <Text style={footer}>
            If you didn't create this account, you can safely ignore this email.
          </Text>
        </Container>
      </Body>
    </Html>
  );
}
 
// Style definitions (inline styles are required for email)
const main = {
  backgroundColor: "#f6f9fc",
  fontFamily: '-apple-system, "Segoe UI", Roboto, sans-serif',
};
const container = {
  margin: "0 auto",
  padding: "40px 20px",
  maxWidth: "560px",
};
const heading = {
  fontSize: "24px",
  fontWeight: "bold" as const,
  color: "#1a1a1a",
  marginBottom: "16px",
};
const paragraph = {
  fontSize: "16px",
  lineHeight: "1.6",
  color: "#4a4a4a",
};
const buttonContainer = { textAlign: "center" as const, margin: "32px 0" };
const button = {
  backgroundColor: "#4f46e5",
  color: "#ffffff",
  padding: "12px 32px",
  borderRadius: "8px",
  fontSize: "16px",
  textDecoration: "none",
};
const hr = { borderColor: "#e5e7eb", margin: "24px 0" };
const footer = { fontSize: "12px", color: "#9ca3af" };

Payment Confirmation Template

// src/emails/payment-confirm.tsx
import {
  Html,
  Head,
  Preview,
  Body,
  Container,
  Section,
  Row,
  Column,
  Text,
  Hr,
} from "@react-email/components";
 
interface PaymentConfirmProps {
  userName: string;
  planName: string;
  amount: string;
  currency: string;
  receiptUrl: string;
}
 
export default function PaymentConfirmEmail({
  userName = "User",
  planName = "Pro Plan",
  amount = "$3",
  currency = "USD",
  receiptUrl = "#",
}: PaymentConfirmProps) {
  return (
    <Html lang="en">
      <Head />
      <Preview>Payment confirmed: {planName}{amount}</Preview>
      <Body style={main}>
        <Container style={container}>
          <Text style={heading}>Payment Confirmed</Text>
          <Text style={paragraph}>
            Hi {userName}, your payment for the {planName} has been
            successfully processed.
          </Text>
          <Section style={receiptBox}>
            <Row>
              <Column><Text style={label}>Plan</Text></Column>
              <Column><Text style={value}>{planName}</Text></Column>
            </Row>
            <Hr style={hr} />
            <Row>
              <Column><Text style={label}>Amount</Text></Column>
              <Column><Text style={value}>{amount} ({currency})</Text></Column>
            </Row>
          </Section>
          <Text style={footerText}>
            You can download your receipt <a href={receiptUrl} style={link}>here</a>.
          </Text>
        </Container>
      </Body>
    </Html>
  );
}
 
const main = {
  backgroundColor: "#f6f9fc",
  fontFamily: '-apple-system, "Segoe UI", Roboto, sans-serif',
};
const container = { margin: "0 auto", padding: "40px 20px", maxWidth: "560px" };
const heading = { fontSize: "24px", fontWeight: "bold" as const, color: "#1a1a1a" };
const paragraph = { fontSize: "16px", lineHeight: "1.6", color: "#4a4a4a" };
const receiptBox = {
  backgroundColor: "#ffffff",
  border: "1px solid #e5e7eb",
  borderRadius: "8px",
  padding: "24px",
  margin: "24px 0",
};
const label = { fontSize: "14px", color: "#6b7280" };
const value = { fontSize: "14px", fontWeight: "bold" as const, textAlign: "right" as const };
const hr = { borderColor: "#e5e7eb" };
const footerText = { fontSize: "14px", color: "#6b7280" };
const link = { color: "#4f46e5" };

Resend Client and API Implementation

Resend Client Setup

// src/lib/email.ts
import { Resend } from "resend";
 
// Initialize Resend client as a singleton
// Fail early if the API key is missing
if (!process.env.RESEND_API_KEY) {
  throw new Error("RESEND_API_KEY is not set");
}
 
export const resend = new Resend(process.env.RESEND_API_KEY);

Email Sending API Route

// src/app/api/send-email/route.ts
import { NextRequest, NextResponse } from "next/server";
import { resend } from "@/lib/email";
import WelcomeEmail from "@/emails/welcome";
import PaymentConfirmEmail from "@/emails/payment-confirm";
 
// Map email types to their templates
const EMAIL_TEMPLATES = {
  welcome: {
    subject: "Welcome to MyApp!",
    component: WelcomeEmail,
  },
  "payment-confirm": {
    subject: "Payment Confirmation",
    component: PaymentConfirmEmail,
  },
} as const;
 
type EmailType = keyof typeof EMAIL_TEMPLATES;
 
export async function POST(req: NextRequest) {
  try {
    const { type, to, props } = await req.json();
 
    // Validate the request
    if (!type || !to || !EMAIL_TEMPLATES[type as EmailType]) {
      return NextResponse.json(
        { error: "Invalid request: type and to are required" },
        { status: 400 }
      );
    }
 
    const template = EMAIL_TEMPLATES[type as EmailType];
    const Component = template.component;
 
    // Send the email via Resend API
    const { data, error } = await resend.emails.send({
      from: "MyApp <noreply@yourdomain.com>",
      to: [to],
      subject: template.subject,
      react: Component(props || {}),
    });
 
    if (error) {
      console.error("Email send error:", error);
      return NextResponse.json({ error: error.message }, { status: 500 });
    }
 
    // Expected output: { id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
    return NextResponse.json({ success: true, id: data?.id });
  } catch (err) {
    console.error("Unexpected error:", err);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 }
    );
  }
}

Supercharging Development with Antigravity Agents

The real power of Antigravity IDE lies in its agent-driven development workflow. Email template creation is an area where this shines particularly bright.

Generating Templates Automatically

In Antigravity's chat panel, you can prompt the agent with specific requirements:

Create a password reset email template using React Email.
- Center a reset link button
- Note that the link expires in 1 hour
- Brand color: #4f46e5
- Include a security notice footer

The agent understands React Email's component API, so it produces correct, email-client-compatible HTML every time.

Preview and Testing

React Email ships with a built-in dev preview server:

# Start the preview server
npx react-email dev --dir src/emails --port 3001
 
# Expected output:
# Ready on http://localhost:3001
# Found 3 email templates

Open http://localhost:3001 in your browser to see a list of all templates. You can preview each email and dynamically adjust props in real time.

Test Delivery with Resend

During development, use Resend's test mode to verify API behavior without sending actual emails:

# Test send via curl
curl -X POST http://localhost:3000/api/send-email \
  -H "Content-Type: application/json" \
  -d '{
    "type": "welcome",
    "to": "test@example.com",
    "props": {
      "userName": "Jane Doe",
      "loginUrl": "https://example.com/login"
    }
  }'
 
# Expected output:
# {"success":true,"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}

Automated Email After Stripe Payments

One of the most common use cases for transactional email is sending payment confirmations after Stripe checkout. Combining Stripe webhooks with Resend makes this fully automatic. For more details on Stripe integration, see "Stripe × Antigravity Payment Implementation Guide."

// src/app/api/webhook/route.ts (excerpt)
import { resend } from "@/lib/email";
import PaymentConfirmEmail from "@/emails/payment-confirm";
 
// Stripe Webhook: send confirmation email on checkout.session.completed
async function handleCheckoutCompleted(session: any) {
  const email = session.customer_details?.email;
  if (!email) return;
 
  await resend.emails.send({
    from: "MyApp <noreply@yourdomain.com>",
    to: [email],
    subject: "Payment Confirmation — MyApp",
    react: PaymentConfirmEmail({
      userName: session.customer_details.name || "Customer",
      planName: session.metadata?.plan_type === "pro" ? "Pro Plan" : "Premium Plan",
      amount: `$${(session.amount_total / 100).toFixed(2)}`,
      currency: session.currency?.toUpperCase() || "USD",
      receiptUrl: session.receipt_url || "#",
    }),
  });
}

Deploying to Production

DNS Configuration for Custom Domain Sending

To send emails from your own domain with Resend, add these DNS records:

# Values displayed in Resend Dashboard → Domains → Add Domain
TXT   _resend        re_xxxx...  # Domain verification
CNAME send._domainkey ...         # DKIM signing
TXT   _dmarc         v=DMARC1; p=none; ...  # DMARC policy

Notes for Cloudflare Workers

When using Resend in a Cloudflare Workers environment, the SDK uses the fetch-based HTTP client, so no special configuration is needed. Just make sure to set your API key with wrangler secret put RESEND_API_KEY.

For more on building serverless APIs, check out "Antigravity × Hono + Cloudflare Workers Serverless API Guide."

Summary

Combining Antigravity IDE with Resend and React Email transforms transactional email development from a tedious chore into a streamlined, AI-assisted workflow. The key takeaways are: component-based template design with React Email, simple delivery logic via Resend's API, full automation through Stripe webhook integration, and accelerated template generation using Antigravity's agents.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Integrations2026-06-28
Where to Start Reading an Unattended Agent's Changes — A Digest for Re-Entry
How do you review the pile of changes an unattended agent left overnight? Not the full diff, not the chat log — a re-entry digest grouped by risk class.
Integrations2026-05-30
Handing Crashlytics Stack Traces to Antigravity — Three Weeks Across Four Apps
Paste a Crashlytics stack trace into Antigravity, let it narrow the cause, and drive the fix to the finish. After three weeks across four wallpaper apps, here is what I learned to delegate and what I kept for myself.
Integrations2026-05-19
Three Weeks of Letting Antigravity Run wrangler tail Across Six Cloudflare Workers
I run six Cloudflare Workers in parallel — four Lab sites and two storytelling blogs — and the morning log review was quietly eating an hour and a half every day. Here is what changed when I handed wrangler tail interpretation to Antigravity's Inline Agent for three weeks, what I trusted it with, and what I kept for myself.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →