PristineSend
Get started
Guides

Deliverability essentials

Getting to the inbox is mostly about looking trustworthy to receiving mail servers. Verify your domain, send only from identities you own, respect the do-not-send list, and ship a plaintext part alongside your html. PristineSend handles the last one for you — the rest are a few minutes of setup.

Verify your sending domain

A verified domain is the foundation of deliverability. Verification proves to inbox providers that you own the domain and lets you publish the records they check on every message: DKIM cryptographically signs your mail, SPF authorizes the sending source, DMARC tells receivers how to handle messages that fail those checks, and a custom MAIL FROM aligns the bounce domain with your own. Together they meaningfully strengthen inbox placement.

Senders

A verified domain can carry multiple sender identities — for example hello@yourdomain.com and billing@yourdomain.com — which you manage in Settings. One sender is the workspace default. When an API send omits from, the workspace default sender is used.

When you do supply from, it must be on a verified domain. A from address whose domain you haven't verified is rejected with 403 sender_not_verified — this is what stops anyone from sending as a domain they don't own.

The suppression list

The suppression list is your workspace's do-not-send list. A hard bounce or a complaint automatically suppresses that recipient, so you stop mailing addresses that damage your reputation. A transactional send to a suppressed address is rejected before it reaches the provider with 403 recipient_suppressed.

You can add, remove, and list entries with the Suppressions API.

// A send to a suppressed address never reaches the provider:
// HTTP 403  { "error": { "code": "recipient_suppressed", ... } }

// Manage the list with the Suppressions API:
"color:#ff7b72">await ps.suppressions.create({ email: "bounced@example.com" })   // add
"color:#ff7b72">await ps.suppressions.delete({ email: "recovered@example.com" }) // remove

One-click unsubscribe

Every campaign send carries the List-Unsubscribe and List-Unsubscribe-Post headers (RFC 8058). Gmail and Yahoo require these for bulk senders and surface a native Unsubscribe link next to your From name — a one-click opt-out that materially improves inbox placement and lowers complaint rates. PristineSend adds them automatically; there is nothing to configure.

A one-click unsubscribe is a marketing opt-out: it suppresses the address for campaigns only. Your transactional mail (receipts, password resets) keeps reaching that recipient — so an automated list-hygiene unsubscribe can never cut off a customer's account email. For that reason these headers are added to campaigns only, never to transactional API sends.

Why multipart matters

Every PristineSend send is multipart: a plaintext alternative is delivered alongside the html. Many spam filters penalize html-only mail, and some clients fall back to the plaintext part — so shipping both improves inbox placement and keeps your message readable everywhere.

With the SDK you get this automatically. Pass html and omit text, and a clean plaintext part is generated for you. The react: convenience renders both the html and the plaintext from your component. Supply your own text only when you want full control over the plaintext part.

"color:#ff7b72">import { PristineSend } "color:#ff7b72">from "pristinesend"

"color:#ff7b72">const ps = "color:#ff7b72">new PristineSend(process.env.PRISTINESEND_API_KEY!)

// Pass html and omit text — a plaintext alternative is auto-generated,
// so the message goes out "color:#ff7b72">as multipart (html + plaintext).
"color:#ff7b72">await ps.emails.send({
  to: "recipient@example.com",
  "color:#ff7b72">from: "hello@yourdomain.com",
  subject: "Your receipt",
  html: "<p>Thanks for your order — view it <a href=">'https://example.com/o/123'>here</a>.</p>",
})

Attachments: host, don't bloat

Heavy attachments hurt you twice: large messages are throttled by the provider and are more likely to be spam-scored. The most reliable pattern is to attach small files inline and host the big ones — keep receipts and short PDFs inline, and for anything sizeable, store the file and link to it (or pass a url attachment, which we fetch at send time and discard — nothing is stored on our side).

// Small file → inline. Large file → host it and link.
"color:#ff7b72">await ps.emails.send({
  to: "customer@example.com",
  subject: "Your invoice",
  html: "<p>Your invoice is attached. Your full statement is <a href=">'https://app.example.com/statements/42'>here</a>.</p>",
  attachments: [
    { filename: "invoice.pdf", content: invoice.toString("base64"), content_type: "application/pdf" },
    // a big "color:#ff7b72">export: host it, pass a url — fetched at send time, never stored
    { filename: "statement.csv", url: "https://files.example.com/statement-42.csv" },
  ],
})

PristineSend enforces this for you: inline attachments are capped to a few MB, a message past the provider ceiling is rejected with message_too_large, and a large-but-sendable message still goes out but returns a soft warnings nudge. Full field reference on the Send page.