1// NOTE: DO NOT EDIT, this file is generated by gendoc.sh.
4Package webapi implements a simple HTTP/JSON-based API for interacting with
5email, and webhooks for notifications about incoming and outgoing deliveries,
6including delivery failures.
10The webapi can be used to compose and send outgoing messages. The HTTP/JSON
11API is often easier to use for developers since it doesn't require separate
12libraries and/or having (detailed) knowledge about the format of email messages
13("Internet Message Format"), or the SMTP protocol and its extensions.
15Webhooks can be configured per account, and help with automated processing of
16incoming email, and with handling delivery failures/success. Webhooks are
17often easier to use for developers than monitoring a mailbox with IMAP and
18processing new incoming email and delivery status notification (DSN) messages.
22The webapi has a base URL at /webapi/v0/ by default, but configurable, which
23serves an introduction that points to this documentation and lists the API
26An HTTP POST to /webapi/v0/<method> calls a method.The form can be either
27"application/x-www-form-urlencoded" or "multipart/form-data". Form field
28"request" must contain the request parameters, encoded as JSON.
30HTTP basic authentication is required for calling methods, with an email address
31as user name. Use a login address configured for "unique SMTP MAIL FROM"
32addresses ("FromIDLoginAddresses" in the account configuration), and configure
33an interval to "keep retired messages delivered from the queue". This allows
34incoming DSNs to be matched to the original outgoing messages, and enables
35automatic suppression list management.
37HTTP response status 200 OK indicates a successful method call, status 400
38indicates an error. The response body of an error is a JSON object with a
39human-readable "Message" field, and a "Code" field for programmatic handling
40(common codes: "user" or user-induced errors, "server" for server-caused
41errors). Most successful calls return a JSON object, but some return data
42(e.g. a raw message or an attachment of a message). See [Methods] for the
43methods and and [Client] for their documentation. The first element of their
44return values indicate their JSON object type or io.ReadCloser for non-JSON
45data. The request and response types are converted from/to JSON. optional and
46missing/empty fields/values are converted into Go zero values: zero for
47numbers, empty strings, empty lists and empty objects. New fields may be added
48in response objects in future versions, parsers should ignore unrecognized
51An HTTP GET to a method URL serves an HTML page showing example
52request/response JSON objects in a form and a button to call the method.
56Webhooks for outgoing delivery events and incoming deliveries are configured
59A webhook is delivered by an HTTP POST with headers "X-Mox-Webhook-ID" (unique
60ID of webhook) and "X-Mox-Webhook-Attempt" (number of delivery attempts,
61starting at 1), and a JSON body with the webhook data. Failing webhook
62deliveries are retried with backoff, each time doubling the interval between
63attempts, at 1m, 2m, 4m, 7.5m, 15m and unwards, until the last attempt after a
66See [webhook.Outgoing] for the fields in a webhook for outgoing deliveries, and
67in particular [webhook.OutgoingEvent] for the types of events.
69Only the latest event for the delivery of a particular outgoing message will be
70delivered, any webhooks for that message still in the queue (after failure to
71deliver) are retired as superseded when a new event occurs.
73Webhooks for incoming deliveries are configured separately from outgoing
74deliveries. Incoming DSNs for previously sent messages do not cause a webhook
75to the webhook URL for incoming messages, only to the webhook URL for outgoing
76delivery events. The incoming webhook JSON payload contains the message
77envelope (parsed To, Cc, Bcc, Subject and more headers), the MIME structure,
78and the contents of the first text and HTML parts. See [webhook.Incoming] for
79the fields in the JSON object. The full message and individual parts, including
80attachments, can be retrieved using the webapi.
84When sending transactional emails, potentially to many recipients, it is
85important to process delivery failure notifications. If messages are rejected,
86or email addresses no longer exist, you should stop sending email to those
87addresses. If you try to keep sending, the receiving mail servers may consider
88that spammy behaviour and blocklist your mail server.
90Automatic suppression list management already prevents most repeated sending
91attempts. The webhooks make it easy to receive failure notifications.
93To keep spam complaints about your messages a minimum, include links to
94unsubscribe from future messages without requiring further actions from the
95user, such as logins. Include an unsubscribe link in the footer, and include
96List-* message headers, such as List-Id, List-Unsubscribe and
101Below are examples for making webapi calls to a locally running "mox
102localserve" with its default credentials.
106 $ curl --user mox@localhost:moxmoxmox \
107 --data request='{"To": [{"Address": "mox@localhost"}], "Text": "hi ☺"}' \
108 http://localhost:1080/webapi/v0/Send
110 "MessageID": "<kVTha0Q-a5Zh1MuTh5rUjg@localhost>",
113 "Address": "mox@localhost",
115 "FromID": "ZfV16EATHwKEufrSMo055Q"
120Send a message with files both from form upload and base64 included in JSON:
122 $ curl --user mox@localhost:moxmoxmox \
123 --form request='{"To": [{"Address": "mox@localhost"}], "Subject": "hello", "Text": "hi ☺", "HTML": "<img src=\"cid:hi\" />", "AttachedFiles": [{"Name": "img.png", "ContentType": "image/png", "Data": "bWFkZSB5b3UgbG9vayE="}]}' \
124 --form 'inlinefile=@hi.png;headers="Content-ID: <hi>"' \
125 --form attachedfile=@mox.png \
126 http://localhost:1080/webapi/v0/Send
128 "MessageID": "<eZ3OEEA2odXovovIxHE49g@localhost>",
131 "Address": "mox@localhost",
133 "FromID": "yWiUQ6mvJND8FRPSmc9y5A"
138Get a message in parsed form:
140 $ curl --user mox@localhost:moxmoxmox --data request='{"MsgID": 424}' http://localhost:1080/webapi/v0/MessageGet
146 "Address": "mox@localhost"
152 "Address": "mox@localhost"
158 "MessageID": "<84vCeme_yZXyDzjWDeYBpg@localhost>",
160 "Date": "2024-04-04T14:29:42+02:00",
162 "Text": "hi \u263a\n",
166 "ContentType": "multipart/mixed",
167 "ContentTypeParams": {
168 "boundary": "0ee72dc30dbab2ca6f7a363844a10a9f6111fc6dd31b8ff0b261478c2c48"
174 "ContentType": "multipart/related",
175 "ContentTypeParams": {
176 "boundary": "b5ed0977ee2b628040f394c3f374012458379a4f3fcda5036371d761c81d"
182 "ContentType": "multipart/alternative",
183 "ContentTypeParams": {
184 "boundary": "3759771adede7bd191ef37f2aa0e49ff67369f4000c320f198a875e96487"
190 "ContentType": "text/plain",
191 "ContentTypeParams": {
199 "ContentType": "text/html",
200 "ContentTypeParams": {
201 "charset": "us-ascii"
210 "ContentType": "image/png",
211 "ContentTypeParams": {},
213 "DecodedSize": 19375,
219 "ContentType": "image/png",
220 "ContentTypeParams": {},
226 "ContentType": "image/png",
227 "ContentTypeParams": {},
242 "MailFromValidated": false,
244 "MsgFromValidated": false,
245 "DKIMVerifiedDomains": [],
247 "MailboxName": "Inbox"
251Errors (with a 400 bad request HTTP status response) include a human-readable
252message and a code for programmatic use:
254 $ curl --user mox@localhost:moxmoxmox --data request='{"MsgID": 999}' http://localhost:1080/webapi/v0/MessageGet
257 "Message": "message not found"
260Get a raw, unparsed message, as bytes:
262 $ curl --user mox@localhost:moxmoxmox --data request='{"MsgID": 123}' http://localhost:1080/webapi/v0/MessageRawGet
263 [message as bytes in raw form]
265Mark a message as read:
267 $ curl --user mox@localhost:moxmoxmox --data request='{"MsgID": 424, "Flags": ["\\Seen", "custom"]}' http://localhost:1080/webapi/v0/MessageFlagsAdd
272A webhook is delivered by an HTTP POST, wich headers X-Mox-Webhook-ID and
273X-Mox-Webhook-Attempt and a JSON body with the data. To simulate a webhook call
274for incoming messages, use:
276 curl -H 'X-Mox-Webhook-ID: 123' -H 'X-Mox-Webhook-Attempt: 1' --json '{...}' http://localhost/yourapp
278Example webhook HTTP POST JSON body for successful outgoing delivery:
282 "Event": "delivered",
284 "Suppressing": false,
286 "FromID": "MDEyMzQ1Njc4OWFiY2RlZg",
287 "MessageID": "<QnxzgulZK51utga6agH_rg@mox.example>",
288 "Subject": "subject of original message",
289 "WebhookQueued": "2024-03-27T00:00:00Z",
291 "SMTPEnhancedCode": "",
296Example webhook HTTP POST JSON body for failed delivery based on incoming DSN
297message, with custom extra data fields (from original submission), and adding address to the suppression list:
305 "FromID": "MDEyMzQ1Njc4OWFiY2RlZg",
306 "MessageID": "<QnxzgulZK51utga6agH_rg@mox.example>",
307 "Subject": "subject of original message",
308 "WebhookQueued": "2024-03-27T00:00:00Z",
310 "SMTPEnhancedCode": "5.4.0",
311 "Error": "timeout connecting to host",
317Example JSON body for webhooks for incoming delivery of basic message:
324 "Address": "mox@localhost"
330 "Address": "mjl@localhost"
337 "MessageID": "<QnxzgulZK51utga6agH_rg@mox.example>",
340 "Date": "2024-03-27T00:00:00Z",
341 "Text": "hello world ☺\n",
344 "ContentType": "text/plain",
345 "ContentTypeParams": {
354 "MailFrom": "mox@localhost",
355 "MailFromValidated": false,
356 "MsgFromValidated": true,
357 "RcptTo": "mjl@localhost",
358 "DKIMVerifiedDomains": [
361 "RemoteIP": "127.0.0.1",
362 "Received": "2024-03-27T00:00:03Z",
363 "MailboxName": "Inbox",
370// NOTE: DO NOT EDIT, this file is generated by gendoc.sh.