# Overview (/docs/integrations)

If your app already sends email through a mail library, an auth framework or a web framework's
mailer, you don't need to rewrite those calls. Point it at coss.com instead.

The JavaScript integrations ship in the [`coss` package](/docs/sdk), so there is nothing else to
install:

```package-install
coss
```

| Integration                                   | Import             | What it replaces                                          |
| --------------------------------------------- | ------------------ | --------------------------------------------------------- |
| [Nodemailer](/docs/integrations/nodemailer)   | `coss/nodemailer`  | SMTP or another transport in `nodemailer.createTransport` |
| [Better Auth](/docs/integrations/better-auth) | `coss/better-auth` | The email callbacks: verification, password reset, magic links, codes, invitations |
| [Auth.js](/docs/integrations/authjs)          | `coss/authjs`      | The email (magic link) provider                           |

Every JavaScript integration reads the API key from `COSS_API_KEY` unless you pass `apiKey`. You
can also pass `client` to reuse a `Coss` client you already have. The client is created on the
first send, so a missing key fails that send, not your app's startup or its build.

The framework drivers are packages of their own, each with no dependency beyond its framework:

| Framework                             | Package                   | What it replaces                               |
| ------------------------------------- | ------------------------- | ---------------------------------------------- |
| [Laravel](/docs/integrations/laravel) | `coss/laravel` (Composer) | The mailer transport (`MAIL_MAILER=coss`)      |
| [Rails](/docs/integrations/rails)     | `coss-rails` (gem)        | Action Mailer's delivery method (`:coss`)      |
| [Django](/docs/integrations/django)   | `coss-django` (pip)       | The email backend (`coss_django.EmailBackend`) |

They read the API key from their own configuration, else `COSS_API_KEY`, and also check it on the
first send rather than at startup.

## How messages are mapped [#how-messages-are-mapped]

The integrations send through the [JSON API](/docs/api-reference) rather than the
[SMTP relay](/docs/email/smtp). That works where outgoing SMTP ports are blocked (serverless
functions, edge runtimes), sets [coss.com's own fields](/docs/email/sending) per message, and gives
you the API's error codes. Each integration turns the library's message into a send request:

- **Addresses** become `Name <address>`, with the name quoted when it contains special characters.
- **Attachments** are sent base64-encoded. One with a Content-ID (`cid`) is sent inline, for
  `<img src="cid:…">`.
- **Headers** that coss.com sets itself (`Message-ID`, `Date`, `MIME-Version`, `Content-Type` and
  similar) are dropped instead of failing the send. Values with non-ASCII characters are encoded as
  RFC 2047 encoded-words. Other headers go through as custom headers (at most 15).
- **What coss.com can't send fails the send instead of being silently dropped**: raw MIME messages, a
  custom SMTP envelope, a separate `Sender`, and AMP bodies.

In JavaScript, coss.com refusals throw a `CossSendError`. It carries the API's error as `error`
and its `code`, `status` and `requestId` (quote the request id to support). These libraries report
failures by throwing, so integrations throw too, unlike `coss.email.send`, which returns
`{ data, error }`. The framework drivers raise their framework's kind of error with the same
fields; see each page.

```ts twoslash
import { CossSendError } from "coss/nodemailer";
declare function send(): Promise<void>;
// ---cut---
try {
  await send();
} catch (err) {
  if (err instanceof CossSendError && err.code === "domain_not_verified") {
    // Verify the sender's domain in the dashboard, or send with a sandbox key.
  }
  throw err;
}
```

## Authentication emails [#authentication-emails]

The Better Auth and Auth.js integrations send with `category: "account"` and turn open and click
tracking off. Click tracking would send the secret sign-in links through coss.com's redirect, and an
`account` category keeps suppressions you scoped to other categories (such as `marketing`) from
blocking sign-in mail.

With a live key, `from` must use a [verified domain](/docs/email/domains). Sandbox keys
(`coss_test_…`) send from any address and never deliver, so they're the way to try an integration
out.
