# Send with SMTP

Source: https://agentboxd.com/docs/smtp

> Send from any SMTP client or library with an API key as the password, through the same pipeline as the API.

Anything that can send email over SMTP can send from your inboxes: a framework’s mailer, a CRM, a printer, `smtplib`. Log in with an API key as the password. The message goes through exactly the same checks and delivery as `POST /v1/inboxes/:id/messages/send`, and shows up in the API and the dashboard like any other sent message.

## Settings

| Setting | Value |
| --- | --- |
| Server | `smtp.agentboxd.com` |
| Port | `587` with STARTTLS (required before login), or `465` with TLS |
| Username | The inbox address (any value works; the address makes the client’s account list readable) |
| Password | An API key (`mr_…`) with the `messages:send` permission |
| Authentication | `PLAIN` or `LOGIN` |

send.ts:

```ts
import nodemailer from 'nodemailer';

const smtp = nodemailer.createTransport({
  host: 'smtp.agentboxd.com',
  port: 587, // STARTTLS; or port: 465, secure: true
  auth: { user: 'support-bot@homingbox.net', pass: process.env.AGENTBOXD_API_KEY },
});

const info = await smtp.sendMail({
  from: 'support-bot@homingbox.net',
  to: 'dana@example.com',
  subject: 'Your refund',
  text: 'Hi Dana, the refund is on its way.',
});
console.log(info.response); // 250 2.0.0 Queued as <message id>
```

send.py:

```python
import os
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "support-bot@homingbox.net"
msg["To"] = "dana@example.com"
msg["Subject"] = "Your refund"
msg.set_content("Hi Dana, the refund is on its way.")

with smtplib.SMTP("smtp.agentboxd.com", 587) as smtp:
    smtp.starttls()
    smtp.login("support-bot@homingbox.net", os.environ["AGENTBOXD_API_KEY"])
    smtp.send_message(msg)
```

## Who you can send as

The envelope sender (`MAIL FROM`) must be one of the key’s inboxes: any inbox of the workspace for a workspace key, only its inbox for an inbox-scoped key. The `From:` header must be the same address. Temporary inboxes are receive-only, and inboxes on a custom domain need the domain verified, as with the API. Otherwise the server answers `550 5.7.1`.

## What happens to the message

- The recipients are the SMTP envelope recipients (up to 50). Each one appears as To or Cc if the header lists it, otherwise it is sent as Bcc.
- Subject, text, HTML and attachments are kept. `From` is set to the inbox address and display name, and the message gets our own Message-ID, as every API send does. Other headers are not carried over, and inline `cid:` images are sent as ordinary attachments.
- `In-Reply-To` and `References` are kept. When they point at a message in the same inbox, the new message joins that thread, and your reply allow/block lists apply as with `POST …/reply`.
- Suppression, allow/block lists, the monthly email quota, the 5-minute burst limit, daily sending caps, size limits (`MAX_MESSAGE_BYTES`) and DKIM signing all apply. The message counts toward usage exactly like an API send, and fires `message.sent` (then delivery events) on webhooks and the [event stream](https://agentboxd.com/docs/realtime-events).
- The reply is `250 2.0.0 Queued as <message id>`: fetch it with `GET /v1/messages/:id`.
- Resubmitting a message with the same Message-ID within 24 hours (a client retrying after a timeout) doesn’t send it twice.

## Errors

| Reply | Why |
| --- | --- |
| `535 5.7.8` | Wrong or revoked key, or a key without `messages:send` |
| `538 5.7.11` | Login attempted before STARTTLS on port 587 |
| `553 5.1.3` | A recipient that isn’t one plain email address, for example with quotes, a comment, a comma or a semicolon in it. Only that recipient is refused |
| `550 5.7.1 <code>: …` | Refused by the API rules, e.g. `recipient_suppressed`, `recipient_blocked`, `plan_limit_emails`, or a sender the key can’t use |
| `451 4.7.1 <code>: …` | Try later: `daily_send_limit_exceeded`, the 5-minute burst limit (`rate_limited`, with “retry in N s”) or the key’s per-minute rate limit (shared with its API calls) |
| `451 4.3.2` | The server is busy with too much mail at once. Try again later; mail clients do this by themselves |
| `552 5.3.4` | Message or attachment too large, or a text or HTML body over 2 MB. Send long content as an attachment |
| `554 5.6.0` | More than 500 MIME parts in one message, a subject longer than 998 characters (the API’s limit), a header block over 128 KB, 10,000 lines or 2,000 fields, or the header block of one MIME part over 1 MB |
| `421 4.7.0` | Too many failed logins from your IP; wait 15 minutes |
| `421 Timeout` | Nothing came from your client for 60 seconds, or the server took that long to handle the message. The connection closes. Send the message again; mail clients do this by themselves. If the server had already queued it, the same Message-ID is not sent twice |

> **Careful:** Treat the key like a password: a mail client that stores it can send as every inbox the key covers. Create an inbox-scoped key with only `messages:send` for each client.
