diff options
| -rw-r--r-- | README.md | 78 |
1 files changed, 47 insertions, 31 deletions
@@ -22,41 +22,34 @@ MDA such as Dovecot. systemctl daemon-reload systemctl enable --now mail-ingest.service -## Example client -```ts -export default { - async email(message, env, ctx) { - const res = await fetch("https://example.com/inject", { - method: "POST", - headers: { - "authorization": `Bearer ${env.INGEST_TOKEN}`, - "content-type": "message/rfc822", - "x-envelope-from": message.from, - "x-envelope-to": message.to, - }, - body: message.raw, - }); - - if (!res.ok) { - const detail = await res.text().catch(() => ""); - throw new Error(`ingest ${res.status} ${detail.slice(0, 200)}`); - } - }, -}; -``` +## Protocol -## Response codes +`POST /inject` -| Status | Meaning | Client action | +| Header | Required | Description | |---|---|---| -| `204 No Content` | Message accepted by the MDA | Done | -| `401 Unauthorized` | Missing or wrong bearer token | Fix config; do not retry | -| `413 Payload Too Large` | Body exceeds 26 MiB | Do not retry | -| `422 Unprocessable Entity` | LMTP replied with a permanent error (5xx), e.g. unknown recipient | Do not retry; bounce | -| `503 Service Unavailable` | LMTP unreachable or replied with a temporary error (4xx) | Retry later | +| `authorization` | yes | `Bearer <INGEST_TOKEN>` | +| `content-type` | no | `message/rfc822` | +| `x-envelope-from` | no | SMTP `MAIL FROM` address | +| `x-envelope-to` | no | SMTP `RCPT TO` address, unless `LMTP_RCPT` is set | -Note: `http2lmtp` itself never retries. The client is responsible for -it. +The body is the raw RFC 5322 message. + +```sh +curl -i -X POST http://127.0.0.1:1234/inject \ + -H "authorization: Bearer $INGEST_TOKEN" \ + -H "content-type: message/rfc822" \ + -H "x-envelope-from: [email protected]" \ + -H "x-envelope-to: [email protected]" \ + --data-binary @message.eml +``` + +| Status | Meaning | +|---|---| +| `204` | Delivered. | +| `401` | Missing or invalid token. | +| `422` | LMTP rejected the message permanently (5xx). Do not retry. | +| `503` | LMTP unreachable or rejected temporarily (4xx). Retry later. | ## Environment @@ -80,3 +73,26 @@ LISTEN_ADDR=127.0.0.1:1234 RUST_LOG=http2lmtp=info ``` + +## Example client (cloudflare workers) +```ts +export default { + async email(message, env, ctx) { + const res = await fetch("https://example.com/inject", { + method: "POST", + headers: { + "authorization": `Bearer ${env.INGEST_TOKEN}`, + "content-type": "message/rfc822", + "x-envelope-from": message.from, + "x-envelope-to": message.to, + }, + body: message.raw, + }); + + if (!res.ok) { + const detail = await res.text().catch(() => ""); + throw new Error(`ingest ${res.status} ${detail.slice(0, 200)}`); + } + }, +}; +``` |
