1package webapi
2
3import (
4 "context"
5 "io"
6 "time"
7
8 "github.com/mjl-/mox/webhook"
9)
10
11// todo future: we can have text and html templates, let submitters reference them along with parameters, and compose the message bodies ourselves.
12// todo future: generate api specs (e.g. openapi) for webapi
13// todo future: consider deprecating some of the webapi in favor of jmap
14
15// Methods of the webapi. More methods may be added in the future. See [Client]
16// for documentation.
17type Methods interface {
18 Send(ctx context.Context, request SendRequest) (response SendResult, err error)
19 SuppressionList(ctx context.Context, request SuppressionListRequest) (response SuppressionListResult, err error)
20 SuppressionAdd(ctx context.Context, request SuppressionAddRequest) (response SuppressionAddResult, err error)
21 SuppressionRemove(ctx context.Context, request SuppressionRemoveRequest) (response SuppressionRemoveResult, err error)
22 SuppressionPresent(ctx context.Context, request SuppressionPresentRequest) (response SuppressionPresentResult, err error)
23 MessageGet(ctx context.Context, request MessageGetRequest) (response MessageGetResult, err error)
24 MessageRawGet(ctx context.Context, request MessageRawGetRequest) (response io.ReadCloser, err error)
25 MessagePartGet(ctx context.Context, request MessagePartGetRequest) (response io.ReadCloser, err error)
26 MessageDelete(ctx context.Context, request MessageDeleteRequest) (response MessageDeleteResult, err error)
27 MessageFlagsAdd(ctx context.Context, request MessageFlagsAddRequest) (response MessageFlagsAddResult, err error)
28 MessageFlagsRemove(ctx context.Context, request MessageFlagsRemoveRequest) (response MessageFlagsRemoveResult, err error)
29 MessageMove(ctx context.Context, request MessageMoveRequest) (response MessageMoveResult, err error)
30}
31
32// Error indicates an API-related error.
33type Error struct {
34 // For programmatic handling. Common values: "user" for generic error by user,
35 // "server" for a server-side processing error, "badAddress" for malformed email
36 // addresses.
37 Code string
38
39 // Human readable error message.
40 Message string
41}
42
43// Error returns the human-readable error message.
44func (e Error) Error() string {
45 return e.Message
46}
47
48type NameAddress struct {
49 Name string // Optional, human-readable "display name" of the addressee.
50 Address string // Required, email address.
51}
52
53// Message is an email message, used both for outgoing submitted messages and
54// incoming messages.
55type Message struct {
56 // For sending, if empty, automatically filled based on authenticated user and
57 // account information. Outgoing messages are allowed maximum 1 From address,
58 // incoming messages can in theory have zero or multiple, but typically have just
59 // one.
60 From []NameAddress
61
62 // To/Cc/Bcc message headers. Outgoing messages are sent to all these addresses.
63 // All are optional, but there should be at least one addressee.
64 To []NameAddress
65 CC []NameAddress
66 // For submissions, BCC addressees receive the message but are not added to the
67 // headers of the outgoing message. Only the message saved the to the Sent mailbox
68 // gets the Bcc header prepended. For incoming messages, this is typically empty.
69 BCC []NameAddress
70
71 // Optional Reply-To header, where the recipient is asked to send replies to.
72 ReplyTo []NameAddress
73
74 // Message-ID from message header, should be wrapped in <>'s. For outgoing
75 // messages, a unique message-id is generated if empty.
76 MessageID string
77
78 // Optional. References to message-id's (including <>) of other messages, if this
79 // is a reply or forwarded message. References are from oldest (ancestor) to most
80 // recent message. For outgoing messages, if non-empty then In-Reply-To is set to
81 // the last element.
82 References []string
83
84 // Optional, set to time of submission for outgoing messages if nil.
85 Date *time.Time
86
87 // Subject header, optional.
88 Subject string
89
90 // For outgoing messages, at least text or HTML must be non-empty. If both are
91 // present, a multipart/alternative part is created. Lines must be
92 // \n-separated, automatically replaced with \r\n when composing the message.
93 // For parsed, incoming messages, values are truncated to 1MB (1024*1024 bytes).
94 // Use MessagePartGet to retrieve the full part data.
95 Text string
96 HTML string
97}
98
99// SendRequest submits a message to be delivered.
100type SendRequest struct {
101 // Message with headers and contents to compose. Additional headers and files can
102 // be added too (see below, and the use of multipart/form-data requests). The
103 // fields of Message are included directly in SendRequest. Required.
104 Message
105
106 // Metadata to associate with the delivery, through the queue, including webhooks
107 // about delivery events. Metadata can also be set with regular SMTP submission
108 // through message headers "X-Mox-Extra-<key>: <value>". Current behaviour is as
109 // follows, but this may change: 1. Keys are canonicalized, each dash-separated
110 // word changed to start with a capital. 2. Keys cannot be duplicated. 3. These
111 // headers are not removed when delivering.
112 Extra map[string]string
113
114 // Additional custom headers to include in outgoing message. Optional.
115 // Unless a User-Agent or X-Mailer header is present, a User-Agent is added.
116 Headers [][2]string
117
118 // Inline files are added to the message and should be displayed by mail clients as
119 // part of the message contents. Inline files cause a part with content-type
120 // "multipart/related" to be added to the message. Optional.
121 InlineFiles []File
122
123 // Attached files are added to the message and should be shown as files that can be
124 // saved. Attached files cause a part with content-type "multipart/mixed" to be
125 // added to the message. Optional.
126 AttachedFiles []File
127
128 // If absent/null, regular TLS requirements apply (opportunistic TLS, DANE,
129 // MTA-STS). If true, the SMTP REQUIRETLS extension is required, enforcing verified
130 // TLS along the delivery path. If false, TLS requirements are relaxed and
131 // DANE/MTA-STS policies may be ignored to increase the odds of successful but
132 // insecure delivery. Optional.
133 RequireTLS *bool
134
135 // If set, it should be a time in the future at which the first delivery attempt
136 // starts. Optional.
137 FutureRelease *time.Time
138
139 // Whether to store outgoing message in designated Sent mailbox (if configured).
140 SaveSent bool
141}
142
143type File struct {
144 Name string // Optional.
145 ContentType string // E.g. application/pdf or image/png, automatically detected if empty.
146 ContentID string // E.g. "<randomid>", for use in html email with "cid:<randomid>". Optional.
147 Data string // Base64-encoded contents of the file. Required.
148}
149
150// MessageMeta is returned as part of MessageGet.
151type MessageMeta struct {
152 Size int64 // Total size of raw message file.
153 DSN bool // Whether this message is a DSN.
154 Flags []string // Standard message flags like \seen, \answered, $forwarded, $junk, $nonjunk, and custom keywords.
155 MailFrom string // Address used during SMTP "MAIL FROM" command.
156 MailFromValidated bool // Whether SMTP MAIL FROM address was SPF-validated.
157 MsgFrom string // Address used in message "From" header.
158 MsgFromValidated bool // Whether address in message "From"-header was DMARC(-like) validated.
159 DKIMVerifiedDomains []string // Verified domains from DKIM-signature in message. Can be different domain than used in addresses.
160 RemoteIP string // Where the message was delivered from.
161 MailboxName string
162}
163
164type SendResult struct {
165 MessageID string // "<random>@<domain>", as added by submitter or automatically generated during submission.
166 Submissions []Submission // Messages submitted to queue for delivery. In order of To, CC, BCC fields in request.
167}
168
169type Submission struct {
170 Address string // From original recipient (to/cc/bcc).
171 QueueMsgID int64 // Of message added to delivery queue, later webhook calls reference this same ID.
172 FromID string // Unique ID used during delivery, later webhook calls reference this same FromID.
173}
174
175// Suppression is an address to which messages will not be delivered. Attempts to
176// deliver or queue will result in an immediate permanent failure to deliver.
177type Suppression struct {
178 ID int64
179 Created time.Time `bstore:"default now"`
180
181 // Suppression applies to this account only.
182 Account string `bstore:"nonzero,unique Account+BaseAddress"`
183
184 // Unicode. Address with fictional simplified localpart: lowercase, dots removed
185 // (gmail), first token before any "-" or "+" (typical catchall separator).
186 BaseAddress string `bstore:"nonzero"`
187
188 // Unicode. Address that caused this suppression.
189 OriginalAddress string `bstore:"nonzero"`
190
191 Manual bool
192 Reason string
193}
194
195type SuppressionListRequest struct{}
196type SuppressionListResult struct {
197 Suppressions []Suppression // Current suppressed addresses for account.
198}
199
200type SuppressionAddRequest struct {
201 EmailAddress string
202 Manual bool // Whether added manually or automatically.
203 Reason string // Free-form text.
204}
205type SuppressionAddResult struct{}
206
207type SuppressionRemoveRequest struct {
208 EmailAddress string
209}
210type SuppressionRemoveResult struct{}
211
212type SuppressionPresentRequest struct {
213 EmailAddress string
214}
215type SuppressionPresentResult struct {
216 Present bool
217}
218
219type MessageGetRequest struct {
220 MsgID int64
221}
222type MessageGetResult struct {
223 Message Message
224 Structure webhook.Structure // MIME structure.
225 Meta MessageMeta // Additional information about message and SMTP delivery.
226}
227
228type MessageRawGetRequest struct {
229 MsgID int64
230}
231
232type MessagePartGetRequest struct {
233 MsgID int64
234
235 // Indexes into MIME parts, e.g. [0, 2] first dereferences the first element in a
236 // multipart message, then the 3rd part within that first element.
237 PartPath []int
238}
239
240type MessageDeleteRequest struct {
241 MsgID int64
242}
243type MessageDeleteResult struct{}
244
245type MessageFlagsAddRequest struct {
246 MsgID int64
247 Flags []string // Standard message flags like \seen, \answered, $forwarded, $junk, $nonjunk, and custom keywords.
248}
249type MessageFlagsAddResult struct{}
250
251type MessageFlagsRemoveRequest struct {
252 MsgID int64
253 Flags []string
254}
255type MessageFlagsRemoveResult struct{}
256
257type MessageMoveRequest struct {
258 MsgID int64
259 DestMailboxName string // E.g. "Inbox", must already exist.
260}
261type MessageMoveResult struct{}
262