> ## Documentation Index
> Fetch the complete documentation index at: https://vlyai-1c28d863.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Resend

> Send transactional and marketing emails from your vly app via Resend. Generous free tier, beautiful developer experience, deliverability built in.

export const Prerequisites = ({items}) => <Note>
    <strong>Before you start.</strong>
    <ul>
      {(items || ["A vly.ai account (free tier is enough)", "A modern browser (Chrome, Firefox, Safari, Edge — all current versions)", "About 10 minutes"]).map((item, i) => <li key={i}>{item}</li>)}
    </ul>
  </Note>;

[Resend](https://resend.com) is a modern email API. Clean docs, generous free tier (3,000 emails/month, 100/day), and deliverability that just works. It's the default email integration in vly for transactional sends.

## Prerequisites

<Prerequisites
  items={[
"A vly project",
"A Resend account (free; sign up at resend.com)",
"A verified domain in Resend (or use the resend.dev test domain)",
"A Resend API key (starts with re_...)"
]}
/>

## Setup

<Steps>
  <Step title="Get your Resend API key">
    1. Sign in at [resend.com/api-keys](https://resend.com/api-keys).
    2. Click **Create API key**.
    3. Name it `vly-yourapp`.
    4. Set permission to **Sending access** (limit by domain if you've verified one).
    5. Copy the key (starts with `re_...`).
  </Step>

  <Step title="Verify a domain (or skip for testing)">
    For production, verify the domain you'll send from:

    1. In Resend, **Domains → Add domain** (e.g., `yourapp.com`).
    2. Add the DNS records Resend shows (4–5 records).
    3. Wait for verification (usually under 5 minutes).

    For testing, you can use `onboarding@resend.dev` as the sender — no domain setup needed.
  </Step>

  <Step title="Connect Resend in vly">
    In a prompt:

    ```text theme={null}
    Send transactional emails via Resend. I'll provide my API key.
    ```

    vly opens the integration setup dialog. Paste your key. The key is stored as `RESEND_API_KEY`.
  </Step>

  <Step title="Use it in a feature">
    ```text theme={null}
    When a new user signs up, send them a welcome email via Resend.
    Sender: hello@yourapp.com. Subject: "Welcome to YourApp". Body
    includes a friendly greeting, a link to /getting-started, and
    a "Reply to talk to us" line.
    ```

    vly creates a Convex action and wires it into the signup flow.
  </Step>
</Steps>

## Configuration

<ParamField path="RESEND_API_KEY" type="string" required>
  Your Resend API key. Server-only. Starts with `re_`.
</ParamField>

<ParamField path="RESEND_FROM_EMAIL" type="string" required>
  Default sender email. Must be from a verified Resend domain (or `onboarding@resend.dev` for testing).
</ParamField>

<ParamField path="RESEND_FROM_NAME" type="string">
  Optional. Display name. Renders as `"Display Name <hello@yourapp.com>"`.
</ParamField>

## Code patterns

### Send a single email

```typescript convex/email.ts theme={null}
import { action } from "./_generated/server";
import { v } from "convex/values";

export const sendWelcome = action({
  args: { to: v.string(), name: v.string() },
  handler: async (_ctx, { to, name }) => {
    const res = await fetch("https://api.resend.com/emails", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.RESEND_API_KEY}`,
        "Content-Type":  "application/json",
      },
      body: JSON.stringify({
        from: `${process.env.RESEND_FROM_NAME} <${process.env.RESEND_FROM_EMAIL}>`,
        to,
        subject: "Welcome to YourApp",
        html: `
          <p>Hi ${name},</p>
          <p>Welcome aboard. Here's where to start: <a href="https://yourapp.com/getting-started">Getting started</a>.</p>
          <p>— The YourApp team</p>
        `,
      }),
    });

    if (!res.ok) {
      throw new Error(`Resend error: ${res.status} ${await res.text()}`);
    }
    return await res.json();
  },
});
```

### Use react-email for templates

For richer emails, use [react-email](https://react.email):

```typescript emails/Welcome.tsx theme={null}
import { Html, Body, Container, Text, Link } from "@react-email/components";

export default function Welcome({ name }: { name: string }) {
  return (
    <Html>
      <Body style={{ fontFamily: "system-ui, sans-serif", padding: 24 }}>
        <Container style={{ maxWidth: 540 }}>
          <Text>Hi {name},</Text>
          <Text>Welcome aboard. Here's where to start:</Text>
          <Link href="https://yourapp.com/getting-started">
            Getting started →
          </Link>
        </Container>
      </Body>
    </Html>
  );
}
```

```typescript convex/email.ts theme={null}
import { render } from "@react-email/render";
import Welcome from "../emails/Welcome";

const html = render(<Welcome name={name} />);
// pass `html` into the Resend API call above
```

vly will set this up if you ask: "Use react-email for the welcome email template."

### Idempotent sends

Avoid duplicate emails on retry by adding an idempotency key:

```typescript theme={null}
body: JSON.stringify({
  from, to, subject, html,
  // Resend doesn't have native idempotency, so dedupe in your DB:
}),

// Before sending, check whether you've already sent this email
const existing = await ctx.runQuery(api.emails.findByKey, { key: idempotencyKey });
if (existing) return existing;

// After sending, record it
await ctx.runMutation(api.emails.recordSend, { key: idempotencyKey, ... });
```

### Webhook: track delivery and bounces

Resend sends webhooks for delivery, open, click, bounce, and complaint events:

```typescript convex/http.ts theme={null}
http.route({
  path: "/api/resend-webhook",
  method: "POST",
  handler: httpAction(async (ctx, req) => {
    const sig  = req.headers.get("svix-signature")!;
    const body = await req.text();

    // (Verify Svix signature — Resend uses Svix for webhooks)

    const event = JSON.parse(body);

    if (event.type === "email.bounced") {
      await ctx.runMutation(api.users.markBounced, { email: event.data.to });
    }

    return new Response(null, { status: 200 });
  }),
});
```

Register the webhook URL in Resend → Webhooks.

## Email templates worth setting up

<CardGroup cols={2}>
  <Card title="Welcome email" icon="hand-wave">
    First impression. Triggered on signup. Keep it short, link to onboarding.
  </Card>

  <Card title="Password reset" icon="key">
    Auto-handled by built-in auth — but you can customize the template.
  </Card>

  <Card title="Email verification" icon="mail-check">
    Auto-handled. Customize the template to match your brand.
  </Card>

  <Card title="Receipt / invoice" icon="receipt">
    Trigger on Stripe `checkout.session.completed`. Include order details and a link to the customer portal.
  </Card>

  <Card title="Notification digest" icon="bell">
    Daily or weekly digest of activity (mentions, assignments, etc.) — gentler than per-event emails.
  </Card>

  <Card title="Magic link" icon="wand">
    For [passwordless auth](/features/auth/passwordless). Auto-handled.
  </Card>
</CardGroup>

## Deliverability tips

<AccordionGroup>
  <Accordion title="Verify your domain" icon="check-circle">
    Sending from a verified domain (with SPF, DKIM, and DMARC) is the single biggest deliverability lever. Don't send production mail from `onboarding@resend.dev`.
  </Accordion>

  <Accordion title="Set up DMARC" icon="shield">
    Resend will guide you through SPF and DKIM during domain verification. DMARC is one extra DNS record (`_dmarc.yourapp.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourapp.com"`). Worth doing.
  </Accordion>

  <Accordion title="Don't send to invalid addresses" icon="alert-triangle">
    Hard bounces hurt your sender reputation. When you get a bounce webhook, mark the address invalid and stop sending.
  </Accordion>

  <Accordion title="Include unsubscribe links" icon="x-circle">
    Required for marketing email; good practice for transactional too. Resend provides a one-click unsubscribe header.
  </Accordion>

  <Accordion title="Warm up new domains slowly" icon="thermometer-sun">
    A brand-new domain sending 10,000 emails on day one looks like spam. Ramp up over a week or two for production sends.
  </Accordion>
</AccordionGroup>

## Cost

Resend's free tier: **3,000 emails/month, 100/day**. Paid plans start at \$20/month for 50,000 emails. For most vly apps, the free tier is more than enough through early production.

## Comparison with alternatives

| Provider | Free tier | Pros | Cons |
| - | - | - | - |
| **Resend** | 3,000/mo, 100/day | Modern API, react-email, fast | Newer, smaller ecosystem |
| [SendGrid](/integrations/sendgrid) | 100/day | Mature, deep features | Older API, complex pricing |
| [Postmark](/integrations/postmark) | 100/mo | Best deliverability, transactional-only | Pricier per email |
| [Mailchimp](/integrations/mailchimp) | 1,000/mo | Marketing-focused | Heavy for transactional |

For most vly apps, **Resend is the recommended default**.

## Troubleshooting

<AccordionGroup>
  <Accordion title="'401 Unauthorized'" icon="alert-triangle">
    API key is wrong or revoked. Re-check `RESEND_API_KEY` in your environment variables.
  </Accordion>

  <Accordion title="'Domain is not verified'" icon="alert-triangle">
    The `from` address uses a domain you haven't verified in Resend. Either verify it or send from `onboarding@resend.dev` for testing.
  </Accordion>

  <Accordion title="Emails arrive in spam" icon="alert-triangle">
    Verify your domain (SPF, DKIM, DMARC). Avoid spammy-sounding subjects. Send from a real-looking sender (`hello@yourapp.com`, not `noreply@yourapp.com`). Don't use ALL CAPS.
  </Accordion>

  <Accordion title="Daily limit hit on free tier" icon="alert-triangle">
    Free tier is 100/day. For higher volume, upgrade to a paid Resend plan.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={3}>
  <Card title="Email campaigns recipe" icon="megaphone" href="/recipes/email-campaigns">
    Send a campaign to a list of users.
  </Card>

  <Card title="Newsletter platform recipe" icon="newspaper" href="/recipes/newsletter-platform">
    Build a complete newsletter app.
  </Card>

  <Card title="Webhooks pattern" icon="webhook" href="/recipes/webhooks">
    The general pattern for handling Resend webhooks.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.