Documentation
Sign inGet started

Send email over SMTP

If your application, framework, or off-the-shelf software already speaks SMTP, you can send through Bird by changing three connection settings and nothing else. Rails ActionMailer, Laravel, Django, WordPress, a scan-to-email printer, an ERP: anything that can submit mail to a relay works. For teams migrating from another provider it is a credentials swap, not an integration.
Mail submitted over SMTP goes through the same pipeline as the email API: the same domain verification, IP pools, DKIM signing, suppression handling, tracking, events, and analytics. SMTP is a second door into one system, not a parallel one.

What you need first

  • A verified sending domain. The address you put in MAIL FROM (and the message From header) must belong to a domain you have verified in this workspace. See Sending domains.
  • An API key with the emails scope. SMTP uses your normal Bird API keys, with no separate SMTP username or password to manage. Create a key with email sending enabled from the API keys page. A key without the emails scope cannot send, and neither can a verify-only key.

Connection settings

Point your client at the SMTP host for your key's region. The region is the prefix in the key itself: a bk_eu1_... key sends through the eu1 host, a bk_us1_... key through us1. Authenticating with a key from the other region fails with a 535 reply naming the host to use instead.
RegionHost
EUeu1.smtp.bird.com
USus1.smtp.bird.com
PortEncryption
465Implicit TLS (SMTPS)
587STARTTLS
2525STARTTLS
Use whichever your client supports:
  • Port 465, implicit TLS (SMTPS). The connection is encrypted from the first byte, before any command is sent. In most libraries this is the "SSL/TLS" or "SMTPS" option.
  • Ports 587 and 2525, STARTTLS. The connection opens in plaintext and upgrades to TLS with the STARTTLS command before authentication. This is the "STARTTLS" option, sometimes labeled plainly "TLS". Pick 2525 if your network blocks 587.
Either way the session is encrypted before your credentials are sent, so they never travel in the clear: on 587 and 2525 Bird refuses AUTH until STARTTLS has run. Port 25 is not offered for submission.

Authenticating

Authenticate with AUTH PLAIN or AUTH LOGIN. The username is the literal string bird, and the password is your API key:
Code example
Username: bird
Password: bk_eu1_your_api_key
The username is a fixed literal; it carries no identity, and the API key in the password field is what authenticates. In most SMTP tools you paste your API key into the password field and set the username to bird. Revoking the key cuts off its SMTP sending within seconds, mid-connection included.

What the message carries, and what the key's config carries

Everything with a natural place in a MIME message comes from the message itself: the From, To, Cc, and Reply-To headers, the subject, the HTML and text bodies, and attachments and inline images. Recipients are taken from the SMTP envelope (RCPT TO). An address in RCPT TO that isn't in a visible To or Cc header is treated as a Bcc. A message can have at most 50 recipients across to, cc, and bcc, and the total message size is capped at 20 MB.
The send options that have no place in a MIME message (which IP pool to send from, the content category, tags, and open/click tracking) come from a per-key SMTP configuration. A key with no configuration sends with sensible defaults: your organization's default pool, the transactional category, and tracking on. To customize them, open the SMTP page and configure the key, or call the SMTP config API. Because the defaults live on the key, you can give each application its own key: a wordpress-prod key on the marketing pool with a source=wordpress tag, an erp key on a dedicated pool, each with no per-message configuration. Editing a key's configuration takes effect on new messages within seconds; you do not need to reconnect or restart your client.

A full session

On port 465 the client opens the TLS connection first, then runs the whole SMTP dialogue inside it:
Code example
   ... TLS handshake ...
S: 220 eu1.smtp.bird.com ESMTP Service Ready
C: EHLO myapp
S: 250-Hello myapp
   250-PIPELINING
   250-8BITMIME
   250-ENHANCEDSTATUSCODES
   250-CHUNKING
   250-AUTH PLAIN LOGIN
   250-SIZE 20971520
   250 LIMITS RCPTMAX=50
C: AUTH PLAIN <base64 of bird + key>
S: 235 2.0.0 Authentication succeeded
C: MAIL FROM:<news@acme.com>
C: RCPT TO:<alice@example.com>
C: DATA
   ... your MIME message ...
C: .
S: 250 2.0.0 Ok: queued as em_01ky7ma8y2es1s2akzk53tmjn0
On port 587 or 2525 the client connects in plaintext, issues STARTTLS to upgrade the connection, then runs the same dialogue inside TLS. AUTH is not offered until the upgrade completes:
Code example
S: 220 eu1.smtp.bird.com ESMTP Service Ready
C: EHLO myapp
S: 250-Hello myapp
   250-PIPELINING
   250-8BITMIME
   250-ENHANCEDSTATUSCODES
   250-CHUNKING
   250-STARTTLS
   250-SIZE 20971520
   250 LIMITS RCPTMAX=50
C: STARTTLS
S: 220 2.0.0 Ready to start TLS
   ... TLS handshake ...
C: EHLO myapp
S: 250-Hello myapp
   250-PIPELINING
   250-8BITMIME
   250-ENHANCEDSTATUSCODES
   250-CHUNKING
   250-AUTH PLAIN LOGIN
   250-SIZE 20971520
   250 LIMITS RCPTMAX=50
C: AUTH PLAIN <base64 of bird + key>
S: 235 2.0.0 Authentication succeeded
C: MAIL FROM:<news@acme.com>
C: RCPT TO:<alice@example.com>
C: DATA
   ... your MIME message ...
C: .
S: 250 2.0.0 Ok: queued as em_01ky7ma8y2es1s2akzk53tmjn0
The final 250 returns the queued message's ID, the same em_... ID you would get from the API. You can look the message up by that ID in the Email log or through GET /v1/email/messages/{message_id}.

Retrying safely

The pipeline accepts a message and delivers it asynchronously, and SMTP clients retry aggressively when a connection drops. To make a retry safe, add an X-Bird-Idempotency-Key header to the message: a repeat within the retention window returns the ID of the message that was already queued instead of sending a second copy. Use a value that is stable for the logical message, like an order ID or a notification ID, not a random one per attempt.

Connection limits

Each organization can hold up to 10 concurrent authenticated SMTP connections by default; the limit can be raised for your organization on request. A connection counts from the moment it authenticates until it closes, across every server and API key in the organization. When you are already at the limit, a further connection is refused with a transient 421 reply once it authenticates: reduce the number of simultaneous connections your senders open, or reuse a connection for several messages, and retry. This is a concurrency limit on open connections, not a cap on how many messages you can send: one connection can submit many messages in sequence. The dashboard SMTP page shows the organization's live connections against the limit.

What comes back

SMTP rejects synchronously everything the API rejects. An unverified sending domain, a recipient on a reserved domain, an unusable IP pool, a blocked attachment type, or a malformed message each come back as a permanent 550 reply at the point the problem is detected, so a misconfigured send fails fast rather than disappearing. An exceeded send quota returns a transient 452, telling well-behaved clients to retry later. Suppressed recipients are the one exception: as with every provider, the message is accepted and the suppressed recipient is dropped downstream, visible in the Email log and events rather than as an SMTP error.

Next steps