mail.go raw
1 package mailinabox
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "net/http"
8 "net/url"
9 "strings"
10 )
11
12 // MailUsers Represents a set of users for a domain.
13 type MailUsers struct {
14 Domain string `json:"domain,omitempty"`
15 Users []User `json:"users,omitempty"`
16 }
17
18 // User Represents a user.
19 type User struct {
20 Email string `json:"email,omitempty"`
21 Privileges []string `json:"privileges,omitempty"`
22 Status string `json:"status,omitempty"`
23 Mailbox string `json:"mailbox,omitempty"`
24 }
25
26 // MailAliases Represents a set of aliases for a domain.
27 type MailAliases struct {
28 Domain string `json:"domain,omitempty"`
29 Aliases []Alias `json:"aliases,omitempty"`
30 }
31
32 // Alias Represents an alias.
33 type Alias struct {
34 Address string `json:"address,omitempty"`
35 AddressDisplay string `json:"address_display,omitempty"`
36 ForwardsTo []string `json:"forwards_to,omitempty"`
37 PermittedSenders []string `json:"permitted_senders,omitempty"`
38 Required bool `json:"required,omitempty"`
39 }
40
41 // MailService Mail API.
42 // https://mailinabox.email/api-docs.html#tag/Mail
43 type MailService service
44
45 // GetUsers Returns all mail users.
46 // https://mailinabox.email/api-docs.html#operation/getMailUsers
47 func (s *MailService) GetUsers(ctx context.Context) ([]MailUsers, error) {
48 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users")
49
50 query := endpoint.Query()
51 query.Set("format", "json")
52 endpoint.RawQuery = query.Encode()
53
54 req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
55 if err != nil {
56 return nil, fmt.Errorf("unable to create request: %w", err)
57 }
58
59 var results []MailUsers
60
61 err = s.client.doJSON(req, &results)
62 if err != nil {
63 return nil, err
64 }
65
66 return results, nil
67 }
68
69 // AddUser Adds a new mail user.
70 // https://mailinabox.email/api-docs.html#operation/addMailUser
71 func (s *MailService) AddUser(ctx context.Context, email, password, privilege string) (string, error) {
72 if email == "" || password == "" || privilege == "" {
73 return "", errors.New("email, password, and privilege are required")
74 }
75
76 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "add")
77
78 data := url.Values{}
79 data.Set("email", email)
80 data.Set("password", password)
81 data.Set("privileges", privilege)
82
83 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
84 if err != nil {
85 return "", fmt.Errorf("unable to create request: %w", err)
86 }
87
88 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
89
90 resp, err := s.client.doPlain(req)
91 if err != nil {
92 return "", err
93 }
94
95 return strings.TrimSpace(string(resp)), nil
96 }
97
98 // RemoveUser Removes an existing mail user.
99 // https://mailinabox.email/api-docs.html#operation/removeMailUser
100 func (s *MailService) RemoveUser(ctx context.Context, email string) (string, error) {
101 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "remove")
102
103 data := url.Values{}
104 data.Set("email", email)
105
106 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
107 if err != nil {
108 return "", fmt.Errorf("unable to create request: %w", err)
109 }
110
111 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
112
113 resp, err := s.client.doPlain(req)
114 if err != nil {
115 return "", err
116 }
117
118 return strings.TrimSpace(string(resp)), nil
119 }
120
121 // AddUserPrivilege Adds a privilege to an existing mail user.
122 // https://mailinabox.email/api-docs.html#operation/addMailUserPrivilege
123 func (s *MailService) AddUserPrivilege(ctx context.Context, email, privilege string) (string, error) {
124 if email == "" || privilege == "" {
125 return "", errors.New("email and privilege are required")
126 }
127
128 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges", "add")
129
130 data := url.Values{}
131 data.Set("email", email)
132 data.Set("privileges", privilege)
133
134 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
135 if err != nil {
136 return "", fmt.Errorf("unable to create request: %w", err)
137 }
138
139 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
140
141 resp, err := s.client.doPlain(req)
142 if err != nil {
143 return "", err
144 }
145
146 return strings.TrimSpace(string(resp)), nil
147 }
148
149 // RemoveUserPrivilege Adds a privilege to an existing mail user.
150 // https://mailinabox.email/api-docs.html#operation/removeMailUserPrivilege
151 func (s *MailService) RemoveUserPrivilege(ctx context.Context, email, privilege string) (string, error) {
152 if email == "" {
153 return "", errors.New("email is required")
154 }
155
156 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges", "remove")
157
158 data := url.Values{}
159 data.Set("email", email)
160 data.Set("privileges", privilege)
161
162 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
163 if err != nil {
164 return "", fmt.Errorf("unable to create request: %w", err)
165 }
166
167 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
168
169 resp, err := s.client.doPlain(req)
170 if err != nil {
171 return "", err
172 }
173
174 return strings.TrimSpace(string(resp)), nil
175 }
176
177 // SetUserPassword Sets a password for an existing mail user.
178 // https://mailinabox.email/api-docs.html#operation/setMailUserPassword
179 func (s *MailService) SetUserPassword(ctx context.Context, email, password string) (string, error) {
180 if email == "" || password == "" {
181 return "", errors.New("email and password are required")
182 }
183
184 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "password")
185
186 data := url.Values{}
187 data.Set("email", email)
188 data.Set("password", password)
189
190 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
191 if err != nil {
192 return "", fmt.Errorf("unable to create request: %w", err)
193 }
194
195 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
196
197 resp, err := s.client.doPlain(req)
198 if err != nil {
199 return "", err
200 }
201
202 return strings.TrimSpace(string(resp)), nil
203 }
204
205 // GetUserPrivileges Returns all privileges for an existing mail user.
206 // https://mailinabox.email/api-docs.html#operation/getMailUserPrivileges
207 func (s *MailService) GetUserPrivileges(ctx context.Context, email string) (string, error) {
208 if email == "" {
209 return "", errors.New("email is required")
210 }
211
212 endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges")
213
214 query := endpoint.Query()
215 query.Set("email", email)
216 endpoint.RawQuery = query.Encode()
217
218 req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
219 if err != nil {
220 return "", fmt.Errorf("unable to create request: %w", err)
221 }
222
223 resp, err := s.client.doPlain(req)
224 if err != nil {
225 return "", err
226 }
227
228 return strings.TrimSpace(string(resp)), nil
229 }
230
231 // GetDomains Returns all mail domains.
232 // https://mailinabox.email/api-docs.html#operation/getMailDomains
233 func (s *MailService) GetDomains(ctx context.Context) ([]string, error) {
234 endpoint := s.client.baseURL.JoinPath("admin", "mail", "domains")
235
236 req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
237 if err != nil {
238 return nil, fmt.Errorf("unable to create request: %w", err)
239 }
240
241 resp, err := s.client.doPlain(req)
242 if err != nil {
243 return nil, err
244 }
245
246 domains := strings.Split(strings.TrimSpace(string(resp)), "\n")
247
248 return domains, nil
249 }
250
251 // GetAliases Returns all mail aliases.
252 // https://mailinabox.email/api-docs.html#operation/getMailAliases
253 func (s *MailService) GetAliases(ctx context.Context) ([]MailAliases, error) {
254 endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases")
255
256 query := endpoint.Query()
257 query.Set("format", "json")
258 endpoint.RawQuery = query.Encode()
259
260 req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
261 if err != nil {
262 return nil, fmt.Errorf("unable to create request: %w", err)
263 }
264
265 var results []MailAliases
266
267 err = s.client.doJSON(req, &results)
268 if err != nil {
269 return nil, err
270 }
271
272 return results, nil
273 }
274
275 // UpsertAlias Adds or updates a mail alias. If updating, you need to set update_if_exists: 1.
276 // https://mailinabox.email/api-docs.html#operation/upsertMailAlias
277 func (s *MailService) UpsertAlias(ctx context.Context, updateIfExists bool, address string, forwardsTo, permittedSenders []string) (string, error) {
278 if address == "" {
279 return "", errors.New("address is required")
280 }
281
282 endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases", "add")
283
284 data := url.Values{}
285 data.Set("update_if_exists", boolToIntStr(updateIfExists))
286 data.Set("address", address)
287 data.Set("forwards_to", strings.Join(forwardsTo, ","))
288 data.Set("permitted_senders", strings.Join(permittedSenders, ","))
289
290 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
291 if err != nil {
292 return "", fmt.Errorf("unable to create request: %w", err)
293 }
294
295 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
296
297 resp, err := s.client.doPlain(req)
298 if err != nil {
299 return "", err
300 }
301
302 return strings.TrimSpace(string(resp)), nil
303 }
304
305 // RemoveAliases Removes a mail alias.
306 // https://mailinabox.email/api-docs.html#operation/removeMailAlias
307 func (s *MailService) RemoveAliases(ctx context.Context, address string) (string, error) {
308 if address == "" {
309 return "", errors.New("address is required")
310 }
311
312 endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases", "remove")
313
314 data := url.Values{}
315 data.Set("address", address)
316
317 req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
318 if err != nil {
319 return "", fmt.Errorf("unable to create request: %w", err)
320 }
321
322 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
323
324 resp, err := s.client.doPlain(req)
325 if err != nil {
326 return "", err
327 }
328
329 return strings.TrimSpace(string(resp)), nil
330 }
331