# Send email from Next.js

> Send email from a Next.js App Router project with Vaartix, including React Email templates and webhooks.

Source: https://vaartix.com/docs/guides/nextjs/

This guide uses the App Router (Next.js 14 and later). Email is sent from the server only: your API key never reaches the browser.

1.  **Install the SDK**

    ```sh
    npm install vaartix
    ```

    Add your key to `.env.local` (and to your host’s environment variables when you deploy):

    .env.local

    ```sh
    VAARTIX_API_KEY=vx_live_...
    ```

    Don’t prefix it with `NEXT_PUBLIC_`. That would ship the key to every visitor’s browser.

2.  **Create a shared client**

    lib/vaartix.ts

    ```ts
    import { Vaartix } from 'vaartix';

    // Reads VAARTIX_API_KEY from the environment.
    export const vaartix = new Vaartix();
    ```

3.  **Send from a Server Action**

    app/contact/actions.ts

    ```tsx
    'use server';

    import { vaartix } from '@/lib/vaartix';

    export async function sendWelcome(formData: FormData) {
      const email = String(formData.get('email'));
      const { data, error } = await vaartix.emails.send({
        from: 'Acme <hello@acme.in>',
        to: email,
        subject: 'Welcome to Acme',
        html: '<p>Thanks for signing up!</p>',
      });
      if (error) return { ok: false, message: error.message };
      return { ok: true, id: data.id };
    }
    ```

    Or from a Route Handler, if another service calls you:

    app/api/send/route.ts

    ```ts
    import { vaartix } from '@/lib/vaartix';

    export async function POST(request: Request) {
      const { to } = await request.json();
      const { data, error } = await vaartix.emails.send({
        from: 'Acme <hello@acme.in>',
        to,
        subject: 'Your report is ready',
        text: 'Download it from your dashboard.',
      });
      if (error) return Response.json({ error }, { status: error.statusCode ?? 500 });
      return Response.json(data);
    }
    ```

Until your domain is verified, send from `@test.vaartix.com` to `delivered@test.vaartix.com`: see [Test mode](https://vaartix.com/docs/sending/test-mode/).

## Templates with React Email

[React Email](https://react.email) lets you write emails as React components. Install it, write a template, and pass it as `react`:

```sh
npm install @react-email/components @react-email/render
```

emails/welcome.tsx

```tsx
import { Body, Button, Container, Heading, Html, Text } from '@react-email/components';

export function WelcomeEmail({ name }: { name: string }) {
  return (
    <Html>
      <Body style={{ fontFamily: 'sans-serif' }}>
        <Container>
          <Heading>Welcome, {name}</Heading>
          <Text>Your account is ready.</Text>
          <Button href="https://acme.in/dashboard">Open your dashboard</Button>
        </Container>
      </Body>
    </Html>
  );
}
```

app/signup/actions.ts

```tsx
'use server';

import { vaartix } from '@/lib/vaartix';
import { WelcomeEmail } from '@/emails/welcome';

export async function onSignup(user: { name: string; email: string }) {
  await vaartix.emails.send(
    {
      from: 'Acme <hello@acme.in>',
      to: user.email,
      subject: 'Welcome to Acme',
      react: <WelcomeEmail name={user.name} />,
    },
    // Safe to retry: the same key never sends twice within 24 hours.
    { idempotencyKey: `welcome-${user.email}` },
  );
}
```

The SDK renders the HTML and a plain-text version for you.

## Receiving webhooks

Verify each webhook against the raw body, so read it with `request.text()` before parsing:

app/api/webhooks/vaartix/route.ts

```ts
import { verifyWebhook, WebhookVerificationError } from 'vaartix';

export async function POST(request: Request) {
  const payload = await request.text();
  try {
    const event = verifyWebhook({
      payload,
      headers: request.headers,
      secret: process.env.VAARTIX_WEBHOOK_SECRET!,
    });
    if (event.type === 'email.bounced') {
      // Stop emailing event.data.recipient
    }
    return new Response(null, { status: 200 });
  } catch (err) {
    if (err instanceof WebhookVerificationError) return new Response(null, { status: 400 });
    throw err;
  }
}
```

Return a 2xx quickly and do slow work afterwards; Vaartix retries anything else. See [Set up webhooks](https://vaartix.com/docs/webhooks/setup/).
