# Sending Emails

> The Prisma stack ships with a mailer system that allows you to send emails from your application. Learn how to use it to send emails.

*Canonical: https://makerkit.dev/docs/nextjs-prisma/emails/sending-emails*

---

Send emails in this repo using `getMailer()` from `@kit/mailers`. The function returns a configured mailer instance based on your `MAILER_PROVIDER` environment variable. Call `mailer.sendEmail({ to, from, subject, text })` for plain text or use the `html` property for HTML emails. Combine it with React Email templates from `@kit/email-templates` for styled transactional emails.

This guide is part of the [Email Configuration](./configuration) documentation.

The `getMailer()` function is a factory that returns the configured mailer instance (Nodemailer or Resend) based on your environment variable, abstracting away provider-specific implementation details.

- **Use `text` when:** sending simple notifications or system alerts. 
- **Use `html` when:** sending branded transactional emails (invitations, receipts, password resets). 
- **Use React Email templates when:** you need maintainable, type-safe email templates with consistent styling. 
- **If unsure:** use React Email templates - the extra setup pays off quickly.

{% sequence title="Steps to send emails" description="Learn how to send emails in MakerKit." %}

[Understanding the Mailer class](#understanding-the-mailer-class)

[Sending an email using the default mailer](#sending-an-email-using-the-default-mailer)

[Sending an HTML email](#sending-an-html-email)

{% /sequence %}

## Understanding the Mailer class

The Mailer class is intentionally minimal:

```tsx
import { z } from 'zod';

import { MailerSchema } from './schema/mailer.schema';

export abstract class Mailer<Res = unknown> {
  abstract sendEmail(data: z.input<typeof MailerSchema>): Promise<Res>;
}
```

The `sendEmail` method is an abstract method that receives Zod-validated input with the following properties: `to`, `from`, `subject`, and either `text` or `html`.

## Sending an email using the default mailer

Once you have configured the mailer provider, you can start sending emails using the `sendEmail` method. Here is an example of how to send an email using the default mailer:

```tsx
import { getMailer } from '@kit/mailers';

async function sendEmail(params: {
  from: string;
  to: string;
}) {
  const mailer = await getMailer();

  return mailer.sendEmail({
    to: params.to,
    from: params.from,
    subject: 'Hello',
    text: 'Hello, World!'
  });
}
```

The `sendEmail` method returns a promise that resolves when the email is sent successfully. If there is an error, the promise will be rejected with an error message.

## Sending an HTML email

If you want to send HTML emails, you can use the `html` property instead of the `text` property:

```tsx
import { getMailer } from '@kit/mailers';

async function sendEmail(params: {
  from: string;
  to: string;
}) {
  const mailer = await getMailer();

  return mailer.sendEmail({
    to: params.to,
    from: params.from,
    subject: 'Hello',
    html: '<h1>Hello, World!</h1>'
  });
}
```

In MakerKit, we wrap all email sending in Server Actions or API routes - never call `getMailer()` from client components since it requires server-side environment variables.

## Common Pitfalls

- **Calling getMailer on the client**: The mailer requires `MAILER_PROVIDER` and credentials only available server-side. Always call from Server Actions, API routes, or server components.
- **Missing await on getMailer**: `getMailer()` returns a Promise. Forgetting `await` causes `sendEmail is not a function` errors.
- **Sending both text and html**: Most providers pick one. If both are provided, `html` takes precedence and `text` is ignored.
- **Hard-coding the from address**: Use `process.env.EMAIL_SENDER` or pass it dynamically. Hard-coded addresses break when changing providers.
- **Not handling errors**: `sendEmail` can throw. Wrap in try/catch and log failures - silent email failures are hard to debug.
- **Large HTML payloads**: Some providers limit email size. Keep HTML under 100KB and use external image URLs instead of inline base64.

{% faq
   title="Frequently Asked Questions"
   items=[
     {"question": "What does the sendEmail method return?", "answer": "The return type depends on the provider. Nodemailer returns message info with messageId. Resend returns { id, from, to, created_at }. The Mailer interface uses unknown to stay provider-agnostic."},
     {"question": "Can I send attachments?", "answer": "Not with the base Mailer interface. For attachments, extend the mailer or use the provider SDK directly. Both Nodemailer and Resend support attachments in their native APIs."},
     {"question": "How do I send to multiple recipients?", "answer": "Pass an array to the 'to' field: to: ['user1@example.com', 'user2@example.com']. For BCC, use the 'bcc' field which most providers support."},
     {"question": "Why is my email not arriving?", "answer": "Check: (1) Mailpit at localhost:8025 for local dev, (2) provider dashboard for send status, (3) spam folder, (4) correct EMAIL_SENDER format for your provider."},
     {"question": "Can I use React Email with plain text emails?", "answer": "Yes. React Email's render() function supports plainText option. Call render(component, { plainText: true }) to get text output instead of HTML."}
   ]
/%}

---

**Next:** [Email Templates →](./templates)
