# SDK field support (/docs/v/0.5.0/adapters/field-support)



Email SDK keeps one message shape, but email APIs do not all expose the same features. This page documents what each Email SDK adapter maps today. Stable adapters either map a field or reject it with a validation error. They should not silently drop message data.

## How to read this page [#how-to-read-this-page]

* `Yes` means the adapter maps that `EmailMessage` field.
* `No` means the adapter rejects that field before calling the provider.
* `Values` means Email SDK sends each tag's value to the provider.
* `One tag` means only one tag can be represented by that provider API. Sending more than one tag fails before the provider request.

## Choose routes by message shape [#choose-routes-by-message-shape]

Fallback routes are only safe when the backup adapter can represent the same message fields that matter to your app. Choose primary and backup routes from the fields your production messages use, not just from provider popularity.

| Need                             | Start with                                               |
| -------------------------------- | -------------------------------------------------------- |
| Most complete API field mapping  | Postmark, SendGrid, AWS SES, Mailgun, Brevo              |
| Resend-style DX with attachments | Resend                                                   |
| Cheap or self-managed delivery   | SMTP                                                     |
| Product/event email              | Loops, Plunk                                             |
| Provider fallback for production | Resend plus SMTP, or one primary API plus Postmark       |
| Attachment-heavy transactional   | Resend, Postmark, SendGrid, Mailgun, Unosend, MailerSend |

If you are unsure, start with Resend for the first send, then choose fallback routes from this table based on the exact fields your app sends. Do not add a fallback adapter until it can represent the same message shape as your primary route.

## Fallback compatibility checklist [#fallback-compatibility-checklist]

* Does the backup adapter support every `EmailMessage` field your message uses?
* Does the backup preserve attachments when receipts, exports, or files matter?
* Does the backup preserve metadata or tags if your app uses them for provider dashboards, analytics, or routing?
* Does the backup support reply-to and headers if support workflows depend on them?
* Has the backup provider account been live-verified in the target environment?

## API adapters [#api-adapters]

These adapters cover most transactional email fields. They are the best fit when your app needs CC, BCC, reply-to, custom headers, tags, metadata, or attachments.

| Adapter                 | CC  | BCC | Reply-To | Headers | Metadata | Tags    | Attachments |
| ----------------------- | --- | --- | -------- | ------- | -------- | ------- | ----------- |
| Resend                  | Yes | Yes | Yes      | Yes     | No       | Yes     | Yes         |
| Postmark                | Yes | Yes | Yes      | Yes     | Yes      | One tag | Yes         |
| SendGrid                | Yes | Yes | Yes      | Yes     | Yes      | Values  | Yes         |
| Cloudflare              | Yes | Yes | Yes      | Yes     | No       | No      | Yes         |
| Unosend                 | Yes | Yes | Yes      | Yes     | No       | Values  | Yes         |
| AWS SES                 | Yes | Yes | Yes      | Yes     | No       | Yes     | Yes         |
| Mailgun                 | Yes | Yes | Yes      | Yes     | Yes      | Values  | Yes         |
| MailerSend              | Yes | Yes | Yes      | Yes     | No       | Values  | Yes         |
| Brevo                   | Yes | Yes | Yes      | Yes     | Yes      | Values  | Yes         |
| Mailchimp Transactional | Yes | Yes | No       | Yes     | Yes      | Values  | Yes         |
| Mailtrap                | Yes | Yes | Yes      | Yes     | Yes      | One tag | Yes         |

## Narrow adapters [#narrow-adapters]

These adapters are useful, but their public APIs do not match the full `EmailMessage` shape. Email SDK keeps them stable by rejecting fields it cannot represent.

| Adapter   | CC  | BCC | Reply-To | Headers | Metadata | Tags   | Attachments |
| --------- | --- | --- | -------- | ------- | -------- | ------ | ----------- |
| SparkPost | No  | No  | Yes      | Yes     | Yes      | Values | Yes         |
| Loops     | No  | No  | No       | No      | Yes      | No     | Yes         |
| Plunk     | No  | No  | Yes      | Yes     | Yes      | No     | Yes         |
| Scaleway  | Yes | Yes | Yes      | Yes     | No       | No     | Yes         |
| ZeptoMail | Yes | Yes | Yes      | No      | No       | No     | Yes         |
| MailPace  | Yes | Yes | Yes      | No      | No       | No     | No          |

## SMTP transport [#smtp-transport]

SMTP is built in and does not use Nodemailer. It maps address fields and headers directly to the SMTP message, but it does not map provider-only concepts like tags or metadata.

| Adapter | CC  | BCC | Reply-To | Headers | Metadata | Tags | Attachments |
| ------- | --- | --- | -------- | ------- | -------- | ---- | ----------- |
| SMTP    | Yes | Yes | Yes      | Yes     | No       | No   | No          |

## Validation behavior [#validation-behavior]

Unsupported fields fail fast. For example, Resend rejects `metadata`, Mailchimp Transactional rejects `replyTo`, and SMTP rejects attachments. Fail-fast validation protects fallback routes from silent data loss: if a field matters, you find out before the provider request.

Loops attachments map to the provider's transactional attachments payload. Loops documents that transactional attachments require support enablement on the account, so accounts without that enablement should omit `attachments`.

The SDK's local checks are not a live deliverability guarantee. Provider accounts still need verified senders or domains, the correct region, API scopes, and any sandbox or recipient allow-list configuration required by that service.

## Attachment rules [#attachment-rules]

Attachment `content` is treated as raw content by default and encoded to Base64 for API adapters that require Base64.

```ts
attachments: [
  {
    filename: "receipt.txt",
    content: "Thanks for your order.",
    contentType: "text/plain",
  },
];
```

If you already have Base64 content, mark it:

```ts
attachments: [
  {
    filename: "receipt.pdf",
    content: base64Pdf,
    contentEncoding: "base64",
    contentType: "application/pdf",
  },
];
```

Adapters that support attachments can also read a local path:

```ts
attachments: [
  {
    filename: "receipt.pdf",
    path: "./receipt.pdf",
    contentType: "application/pdf",
  },
];
```
