SMTP

Send through COSS from anything that speaks SMTP, with an API key as the password.

Apps that can only send over SMTP, such as Supabase Auth, WordPress, Rails, Laravel, Django, nodemailer setups and older software, can send through COSS's SMTP relay. A message sent this way is turned into the same request as POST /v1/emails. It gets the same sender checks, suppressions, quotas, tracking, webhooks and logs.

The key decides where the email goes, exactly as with the API. A sandbox key (coss_test_…) sends from a sandbox environment and nothing leaves COSS. A live key sends for real, from a verified domain. The key needs the email:send permission.

Encryption is required. Use port 465 for TLS from the first byte, or 587 with STARTTLS; COSS refuses AUTH before TLS. If your host blocks outgoing 465 and 587 (some cloud providers do), use 2465 or 2587.

Frameworks

import nodemailer from "nodemailer";

const transport = nodemailer.createTransport({
  host: "smtp.coss.com",
  port: 465,
  secure: true,
  auth: { user: "coss", pass: process.env.COSS_API_KEY },
});

await transport.sendMail({
  from: "Acme <hello@acme.com>",
  to: "ada@example.com",
  subject: "Welcome",
  html: "<p>Thanks for signing up!</p>",
});

How a message becomes an email

  • Sender: the From header, which must name exactly one address. With a live key it must be on a verified domain. The envelope sender (MAIL FROM) is ignored; COSS uses its own return path for bounces.
  • Recipients: the envelope (RCPT TO) decides who receives the message, at most 50 per message. Addresses in the To and Cc headers stay to and cc, and every other envelope recipient becomes bcc. A To or Cc address that isn't an envelope recipient is refused, because COSS can't show a recipient without sending to them. So is a message with no To recipient; COSS won't move Bcc'd addresses into To.
  • Content: Subject is required, plus an HTML part, a text part or both. Attachments keep their file names, and parts without one get a generated name. Inline images (cid:) stay inline. The attachment limits apply: 20 files, 25 MB combined, and no executable types.
  • Headers: up to 15 custom headers are sent on, such as In-Reply-To, References, List-Unsubscribe and X-…. Transport headers (Message-ID, Date, MIME-Version, Content-*, Received, DKIM-Signature) and mail-client headers (X-Mailer, User-Agent) are dropped. COSS sets its own Message-ID, so threads continue through In-Reply-To and References, not your original id.
  • Size: at most 40 MB per message, as advertised by SIZE.

COSS headers

These headers set what the API takes as fields. COSS reads them and doesn't send them on.

unsubscribe adds one-click unsubscribe headers, so it needs an X-Coss-Category and a single recipient, like the API's tracking.unsubscribe.

SMTP clients retry when a connection drops before COSS answers. With an X-Coss-Idempotency-Key, a retry gets the first email back instead of sending a second one.

Replies

A 250 reply means COSS has accepted the email. It names the email's id, which you can look up with coss.email.get(): 250 2.0.0 OK queued as email_01…. Delivery then happens just as it does for API sends: follow it with webhooks or in the dashboard. Every message also appears in the environment's logs with source smtp, without addresses or content.

Messages sent over SMTP share their API key's rate limit and the organization's send quotas with API sends.