# IMAP and SMTP

> Open a Pidgeon mailbox in Apple Mail, Thunderbird, an agent or a script that speaks IMAP and SMTP, using an app password rather than your account.

IMAP and SMTP are on every plan, free included. That is not generosity: a
product people stay with because leaving is painful is a product that has
stopped having to be good.

## Hosts

```text
IMAP   imap.pidgeon.ai   port 993   TLS
SMTP   smtp.pidgeon.ai   port 465   TLS
```

Both are implicit TLS. There is no STARTTLS port and no plaintext port, so
there is no way to configure a client that connects without encryption.

## App passwords

Your account has no password — sign-in is a one-time link — so a mail client,
an agent or a script gets its own credential instead. Create one per client
under **Inboxes → Mail apps and agents**, and name it after the device or the
agent you are setting up.

An app password is shown once, is scoped to a single mailbox, and can be
revoked on its own. Revoking one does not sign you out anywhere else, which is
what makes "I have lost that laptop" a thirty-second job.

The username is the full address.

```text
Username   hello@yourdomain.com
Password   the app password, not your account
```

The two go together: a password presented for the wrong address is a failed
login, not a successful one.

### Issuing them from software

`POST /v1/app-passwords` does the same thing with an API key, which is how a
platform hands its own customer a working mail client without either of you
opening a settings screen.

```text
POST /v1/app-passwords
{ "identity_id": "…", "name": "Customer laptop" }

→ { "username": "acme@yourdomain.com", "password": "…" }
```

You can only issue one for an address your key can already **send** from. The
credential reads that inbox and sends as the address, so issuing one is
handing over exactly that — a key that may only read an address cannot mint
itself the ability to answer from it.

## Setting one up

Two procedures, not one per client: Apple Mail installs a profile and answers
every question itself, and everything else — Outlook, other mail apps, agents
and scripts — is the same eight fields typed by hand.

### Apple Mail

**Inboxes → Mail apps and agents → Apple Mail → Set up.** A Mac downloads a
configuration profile; a phone or iPad points its camera at the QR code, which
is the same profile over a link that works once.

The install sheet should say **Verified** in green and name `pidgeon.ai` as
the signer. Nothing is typed — no host, no port, no TLS checkbox, no username
in a field the client labels optional — and the app password is created and
named after the device while the profile installs. Each device gets its own,
so setting up a phone does not disturb a Mac.

If the sheet asks you for a password, something is wrong: the profile carries
one and it is never shown. Say so rather than guessing at it.

### Outlook

Outlook does not read a configuration profile, so it is the manual path:
**Inboxes → Mail apps and agents → Outlook → Set up** creates the app password and
shows every field beside it.

In Outlook, add an account, enter the address, and choose **IMAP** when it
offers account types. Then open the advanced or manual settings rather than
letting it configure itself — left alone it picks port 587 for sending, which
is not served here, and reports a server it cannot reach rather than a port it
should not have chosen.

```text
Incoming   imap.pidgeon.ai   993   SSL/TLS
Outgoing   smtp.pidgeon.ai   465   SSL/TLS
Username   your full address, both boxes
Password   the app password
```

**One thing worth knowing before you choose Outlook.** The new Outlook for
Windows does not connect to an IMAP server from your machine — it hands the
account to Microsoft, whose servers fetch and store your mail so that their
app can show it. Classic Outlook and Outlook for Mac speak IMAP directly. If
the point of your own domain on your own inbox was that the mail is yours,
that difference is the whole of it.

### Any other client

Thunderbird, Spark, K-9, mutt, anything that speaks IMAP: **Inboxes → Mail
apps and agents → Other mail apps → Set up**, then the four rules under Hosts
above.

Thunderbird finds the right settings on its own once the address and app
password are entered, and offers IMAP and POP3 — take IMAP. POP3 downloads the
mail and takes it off the server, which is a different product.

### Agents and scripts

Hermes Agent's email gateway, a Python script with `imaplib` and `smtplib`,
anything that logs in over IMAP and SMTP rather than calling the API:
**Inboxes → Mail apps and agents → An agent or a script → Get a password**.
Name it after the agent, so disconnecting it later leaves your mail apps
alone. The dialog shows the username, the password and both hosts; the agent
takes the same four values a mail client does.

```text
IMAP host   imap.pidgeon.ai   993, TLS from the first byte
SMTP host   smtp.pidgeon.ai   465, TLS from the first byte
Username    the full address
Password    the app password
```

Most libraries need telling that both ports are implicit TLS: `IMAP4_SSL` and
`SMTP_SSL` in Python, not `starttls()`. Software that already holds an API key
can issue its own with `POST /v1/app-passwords` (above) instead of anybody
opening this screen. An agent that speaks MCP or calls the API does not need
one at all.

## What syncs

Folders are derived rather than stored — they are predicates over your mail,
and IMAP sees a UID projection of them. Flags written from a client come
back: marking read in Apple Mail marks read here, and moving a message to
Archive archives it.

Six mailboxes, under the names IMAP expects rather than the ones the web
client shows:

| IMAP      | Special-use | Here    |
| --------- | ----------- | ------- |
| `INBOX`   | —           | Inbox   |
| `Sent`    | `\Sent`     | Sent    |
| `Drafts`  | `\Drafts`   | Drafts  |
| `Archive` | `\Archive`  | Archive |
| `Junk`    | `\Junk`     | Spam    |
| `Trash`   | `\Trash`    | Trash   |

**`Junk`, not `Spam`** — that is the name every mail client looks for, and
the special-use attribute is how Apple Mail finds it without guessing.
**Starred is not a mailbox**: it is the `\Flagged` flag, because a starred
message is still in whichever folder it is in, and a mailbox would put it in
two places. A script that does `SELECT Spam` or `SELECT Starred` gets `NO [No
such mailbox]`, and this table is what it should have read.

Your labels appear as mailboxes too, under their own names, holding what you
have labelled.

### Which flags stick

`\Seen` and `\Flagged` are stored, and `\Deleted` is held until your next
`EXPUNGE` — those three are what the mailbox advertises in `PERMANENTFLAGS`.
Anything else a client sets is accepted and dropped.

### What EXPUNGE does

In **Drafts**, `EXPUNGE` discards the drafts you flagged `\Deleted`, as
**Discard** does in Pidgeon. Apple Mail saves a new copy of the email you are
writing every thirty seconds and removes the previous one this way, so those
copies never reach Trash.

Everywhere else it removes nothing and reports what has left the mailbox. A
mail client never permanently deletes anything here: deleting is a move to
Trash, and you empty Trash in Pidgeon.

A `\Deleted` flag stays on the connection that set it. Expunge from the same
connection, which is what every mail client does.

### Copying into a folder moves

A message is one row and the folders are views of its flags, so it cannot be
in two of them — "copy to Archive" has no second copy to make, and we perform
the move.

This is not pedantry. **Apple Mail archives with `COPY`**, not `MOVE`: it
sends `UID COPY`, then `STORE +FLAGS (\Deleted)`, then `EXPUNGE`, and it does
that even though the server advertises `MOVE`. Refusing the copy — which we
did until October 2026 — broke every archive and every "mark as spam" from
Mail, with the message reappearing a second later and nothing to say why.

Copying into a **label** is a real copy, because a label is a row and a
message can hold several.

### UIDs do not come back

A message that leaves a mailbox and returns gets a **new, higher** UID, which
is precisely what IMAP means by the old one having been expunged and
something new having arrived. Clients handle this; scripts that cache a UID
across a move do not.

## What does not

Server-side rules, IMAP `NOTIFY`, and shared folders between accounts. If one
of those is the reason you are here, it is not built and it is not scheduled.

## When a client will not connect

**Submission is 465 only.** There is no 587, deliberately: STARTTLS means the
mail server upgrades the connection itself, and it does not hold the
certificate. A client configured for 587 does not get a refusal — the
connection is accepted and then nothing answers it, which most clients report
as a timeout or "could not connect to this SMTP server" with no detail. If
that is what you are looking at, check the port before anything else.

**Which clients are actually walked:** Apple Mail on macOS, by hand, against
production. Thunderbird and iOS Mail speak the same subset and are expected
to work; they are not part of the release script, so if one of them is your
client and something is wrong, say so and it becomes a case rather than a
guess.

## Sending from a client

SMTP submission goes through the same guard as everything else — the same
daily allowance, the same suppression list, the same abuse checks. A client
cannot send as an address the app password does not own, and trying is
refused rather than silently rewritten.
