# Proton Bridge — SMTP Reference

## Connection Parameters

### Via Proton Bridge (Local)
| Parameter | Value |
|-----------|-------|
| Host | `127.0.0.1` or `localhost` |
| Port | `1025` (default; configurable) |
| Encryption | STARTTLS (default); switchable to implicit TLS (SSL) in Bridge settings |
| Authentication | PLAIN or LOGIN |
| Username | Full Proton Mail email address (e.g. `user@protonmail.com` or `user@proton.me`) |
| Password | Bridge password (generated by Bridge; NOT your Proton login password) |

### Via Proton SMTP Relay (Direct, no Bridge)
| Parameter | Value |
|-----------|-------|
| Host | `smtp.protonmail.ch` |
| Port | `587` |
| Encryption | STARTTLS |
| Authentication | PLAIN or LOGIN |
| Username | Custom domain email address only (requires paid plan + custom domain) |
| Password | SMTP token (generated in Proton web UI; NOT your login password or Bridge password) |

## Nodemailer Configuration (Bridge)

The recommended nodemailer configuration for connecting via a local Bridge instance:

```javascript
// Recommended: with exported Bridge certificate
nodemailer.createTransport({
  host: "127.0.0.1",
  port: 1025,
  secure: false,         // false = STARTTLS, not implicit TLS
  requireTLS: true,      // Reject if STARTTLS upgrade fails
  auth: {
    user: "you@protonmail.com",
    pass: "<bridge-password>",  // NOT your Proton login password
  },
  tls: {
    ca: [fs.readFileSync("/path/to/cert.pem")],  // Exported Bridge cert
    minVersion: "TLSv1.2",
  },
});

// Fallback: without certificate (insecure but functional on localhost)
nodemailer.createTransport({
  host: "127.0.0.1",
  port: 1025,
  secure: false,
  auth: { user: "you@protonmail.com", pass: "<bridge-password>" },
  tls: {
    rejectUnauthorized: false,  // Disable cert validation — localhost only
    minVersion: "TLSv1.2",
  },
});
```

Important: `secure: false` does NOT mean unencrypted — it means "don't use implicit TLS wrapping from the start; use STARTTLS upgrade instead." The connection is still encrypted after the STARTTLS handshake.

## SMTP Token vs Bridge Password

These are two entirely different authentication mechanisms:

| | Bridge Password | SMTP Token |
|---|---|---|
| Used with | Local Bridge (port 1025) | Direct Proton relay (smtp.protonmail.ch:587) |
| Generated by | Bridge automatically | User manually in Proton web interface |
| Stored | OS keychain | Shown once in Proton web UI; user must copy it |
| Scope | All addresses in combined mode | Single specific address |
| Multiple instances | One per Bridge install | One per client/use-case (recommended) |
| Rotation | Regenerate in Bridge settings | Delete old token, create new one |
| Requirement | Paid account + Bridge installed | Paid account + custom domain only |

### When to Use Each

**Use Bridge password** when:
- Running Bridge locally (the typical setup)
- Connecting to port 1025 on localhost
- You want end-to-end encryption (Bridge encrypts before sending upstream)

**Use SMTP token** when:
- You want to send email from a server or application WITHOUT installing Bridge
- You have a custom domain on a paid Proton plan
- You're connecting directly to `smtp.protonmail.ch:587`
- Note: Email sent this way is stored with zero-access encryption but is NOT end-to-end encrypted

## Generating an SMTP Token

1. Log in to Proton Mail web interface
2. Navigate to Settings → All settings → Encryption and keys → Email encryption keys
   — OR — Settings → All settings → IMAP/SMTP → SMTP tokens
3. Click "Generate token"
4. Give it a descriptive name (e.g., "MCP Server")
5. Copy the token immediately — it is shown only once
6. The token cannot be retrieved later; if lost, delete it and generate a new one

Each token is associated with a specific address. Multiple tokens can exist simultaneously and each can be revoked independently.

## Authentication Details

Bridge supports PLAIN and LOGIN SASL mechanisms. As of Bridge v3.16.0 (released January 2025), IMAP AUTHENTICATE PLAIN is explicitly supported. For SMTP the same mechanisms apply.

The username must be the full email address. Using just the local part (without the domain) will fail authentication.

## Port Configuration

Default SMTP port: **1025**

To change the port in Bridge: Settings → Advanced settings → Default ports → Change (SMTP)

If port 1025 is occupied, increment by one (1026, 1027, etc.) until an available port is found. The MCP server config must be updated to match.

## TLS Mode Details

### STARTTLS (default for port 1025)

The connection lifecycle:
1. Client connects to port 1025 (no encryption yet)
2. Client sends `EHLO`, server responds with capabilities including `STARTTLS`
3. Client sends `STARTTLS` command
4. TLS handshake occurs using Bridge's self-signed certificate
5. Client authenticates and sends mail, all over the encrypted connection

If the STARTTLS upgrade fails and `requireTLS: true` is set in nodemailer, the connection is aborted rather than sending credentials in cleartext.

### Implicit TLS / SSL

When Bridge is configured to use SSL instead of STARTTLS:
- The TLS connection is established before any SMTP commands
- Set `secure: true` in nodemailer
- The port remains 1025 by default (can be reconfigured)

## Attachment Limits

Proton Mail enforces a 25 MB per-attachment limit and 25 MB total per email. The MCP server enforces these same limits client-side before attempting to send:
- Maximum 20 attachments per email
- 25 MB per individual attachment
- 25 MB total across all attachments

Note: These are Proton's enforced limits. Emails that exceed them will be rejected by Bridge even if the MCP server doesn't catch them first.

## Recipient Limits

There is no officially documented maximum recipient count in Bridge's own documentation, but the MCP server applies a 50-recipient cap (To + CC + BCC combined) as a defense-in-depth measure against spam amplification.

Proton Mail's web interface enforces its own limits which may differ. Large bulk sends through Bridge may be rate-limited or rejected by Proton's upstream servers.

## Known Quirks and Issues with Node.js/Nodemailer

### 1. Self-Signed Certificate Rejection
Node.js will throw `CERT_HAS_EXPIRED`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, or `DEPTH_ZERO_SELF_SIGNED_CERT` when connecting to Bridge without either trusting the certificate or disabling validation. Solution: export the cert from Bridge and pass it as `tls.ca`.

### 2. `secure: false` is Correct for Port 1025
Many developers misread this as "insecure". It means "do not use implicit TLS on connect". The connection will still be encrypted after STARTTLS. Setting `secure: true` on port 1025 will cause a connection failure because Bridge expects STARTTLS on that port by default.

### 3. Connection Pooling
Nodemailer's connection pool may hold connections open. Bridge does not have known issues with persistent SMTP connections, but if Bridge is restarted while a connection is pooled, the next send will fail. The MCP server creates a single transporter on startup; if Bridge is restarted, the server needs to be restarted too (or the transporter re-initialized).

### 4. No Separate Sent-Folder Write via SMTP
Bridge automatically saves sent emails to the Proton Sent folder via its API. Unlike some IMAP setups, you do NOT need to manually append a copy to the Sent folder after sending via SMTP — Bridge handles this transparently.

### 5. SMTP Token vs Bridge Password Not Interchangeable
The SMTP token (for `smtp.protonmail.ch`) will NOT work on `localhost:1025`, and the Bridge password will NOT work on `smtp.protonmail.ch`. Mixing these up is a common configuration error.

### 6. Username Format for Proton.me Addresses
Both `user@protonmail.com` and `user@proton.me` formats should work as usernames, but the recommended format is whichever is the account's primary address. The aerc documentation notes that `proton.me` domain users should substitute accordingly.

### 7. Bridge Must Be Running
If Bridge is not running, SMTP connections to `localhost:1025` will be refused immediately with `ECONNREFUSED`. The MCP server should handle this gracefully and surface a clear error rather than a raw stack trace.

## Security Considerations

- The Bridge password is generated by Bridge and stored in the OS keychain — it should never be committed to source control or logged
- SMTP tokens should also be treated as secrets with the same care as passwords
- When `rejectUnauthorized: false` is used (no cert configured), a local process on the same machine could theoretically intercept the SMTP traffic
- Bridge implements TLS certificate public key pinning for its upstream connection to Proton servers, providing strong protection against MITM on the server side

## Sources

- https://proton.me/support/smtp-submission
- https://proton.me/support/port-already-occupied-error
- https://dev.to/polluterofminds/how-to-use-protonmail-with-nodemailer-5c4l
- https://proton.me/blog/bridge-security-model
- https://protonmail.com/download/bridge/stable_releases.html
- https://mailtrap.io/blog/proton-mail-smtp/
