mailpit-api 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,571 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ MailpitClient: () => MailpitClient
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_axios = __toESM(require("axios"));
37
+ var MailpitClient = class {
38
+ axiosInstance;
39
+ /**
40
+ * Creates an instance of {@link MailpitClient}.
41
+ * @param baseURL - The base URL of the Mailpit API.
42
+ * @param auth - Optional authentication credentials.
43
+ * @param auth.username - The username for basic authentication.
44
+ * @param auth.password - The password for basic authentication.
45
+ * @example No Auth
46
+ * ```typescript
47
+ * const mailpit = new MailpitClient("http://localhost:8025");
48
+ * ```
49
+ * @example Basic Auth
50
+ * ```typescript
51
+ * const mailpit = new MailpitClient("http://localhost:8025", {
52
+ * username: "admin",
53
+ * password: "supersecret",
54
+ * });
55
+ * ```
56
+ */
57
+ constructor(baseURL, auth) {
58
+ this.axiosInstance = import_axios.default.create({
59
+ baseURL,
60
+ auth,
61
+ validateStatus: function(status) {
62
+ return status === 200;
63
+ }
64
+ });
65
+ }
66
+ async handleRequest(request, options = { fullResponse: false }) {
67
+ try {
68
+ const response = await request();
69
+ return options.fullResponse ? response : response.data;
70
+ } catch (error) {
71
+ if ((0, import_axios.isAxiosError)(error)) {
72
+ const url = error.config?.url || "UNKNOWN URL";
73
+ const method = error.config?.method?.toUpperCase() || "UNKNOWN METHOD";
74
+ if (error.response) {
75
+ throw new Error(
76
+ `Mailpit API Error: ${error.response.status.toString()} ${error.response.statusText} at ${method} ${url}: ${JSON.stringify(error.response.data)}`
77
+ );
78
+ } else if (error.request) {
79
+ throw new Error(
80
+ `Mailpit API Error: No response received from server at ${method} ${url}`
81
+ );
82
+ } else {
83
+ throw new Error(
84
+ `Mailpit API Error: ${error.toString()} at ${method} ${url}`
85
+ );
86
+ }
87
+ } else {
88
+ throw new Error(`Unexpected Error: ${error}`);
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Retrieves information about the Mailpit instance.
94
+ *
95
+ * @returns Basic runtime information, message totals and latest release version.
96
+ * @example
97
+ * ```typescript
98
+ * const info = await mailpit.getInfo();
99
+ * ```
100
+ */
101
+ async getInfo() {
102
+ return await this.handleRequest(
103
+ () => this.axiosInstance.get("/api/v1/info")
104
+ );
105
+ }
106
+ /**
107
+ * Retrieves the configuration of the Mailpit web UI.
108
+ * @remarks Intended for web UI only!
109
+ * @returns Configuration settings
110
+ * @example
111
+ * ```typescript
112
+ * const config = await mailpit.getConfiguration();
113
+ * ```
114
+ */
115
+ async getConfiguration() {
116
+ return await this.handleRequest(
117
+ () => this.axiosInstance.get("/api/v1/webui")
118
+ );
119
+ }
120
+ /**
121
+ * Retrieves a summary of a specific message and marks it as read.
122
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
123
+ * @returns Message summary
124
+ * @example
125
+ * ```typescript
126
+ * const message = await mailpit.getMessageSummary();
127
+ * ```
128
+ */
129
+ async getMessageSummary(id = "latest") {
130
+ return await this.handleRequest(
131
+ () => this.axiosInstance.get(
132
+ `/api/v1/message/${id}`
133
+ )
134
+ );
135
+ }
136
+ /**
137
+ * Retrieves the headers of a specific message.
138
+ * @remarks Header keys are returned alphabetically.
139
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
140
+ * @returns Message headers
141
+ * @example
142
+ * ```typescript
143
+ * const headers = await mailpit.getMessageHeaders();
144
+ * ```
145
+ */
146
+ async getMessageHeaders(id = "latest") {
147
+ return await this.handleRequest(
148
+ () => this.axiosInstance.get(
149
+ `/api/v1/message/${id}/headers`
150
+ )
151
+ );
152
+ }
153
+ /**
154
+ * Retrieves a specific attachment from a message.
155
+ * @param id - Message database ID or "latest"
156
+ * @param partID - The attachment part ID
157
+ * @returns Attachment as binary data and the content type
158
+ * @example
159
+ * ```typescript
160
+ * const message = await mailpit.getMessageSummary();
161
+ * if (message.Attachments.length) {
162
+ * const attachment = await mailpit.getMessageAttachment(message.ID, message.Attachments[0].PartID);
163
+ * // Do something with the attachment data
164
+ * }
165
+ * ```
166
+ */
167
+ async getMessageAttachment(id, partID) {
168
+ const response = await this.handleRequest(
169
+ () => this.axiosInstance.get(
170
+ `/api/v1/message/${id}/part/${partID}`,
171
+ { responseType: "arraybuffer" }
172
+ ),
173
+ { fullResponse: true }
174
+ );
175
+ return {
176
+ data: response.data,
177
+ contentType: response.headers["content-type"]
178
+ };
179
+ }
180
+ /**
181
+ * Generates a cropped 180x120 JPEG thumbnail of an image attachment from a message.
182
+ * Only image attachments are supported.
183
+ * @remarks
184
+ * If the image is smaller than 180x120 then the image is padded.
185
+ * If the attachment is not an image then a blank image is returned.
186
+ * @param id - Message database ID or "latest"
187
+ * @param partID - The attachment part ID
188
+ * @returns Image attachment thumbnail as binary data and the content type
189
+ * @example
190
+ * ```typescript
191
+ * const message = await mailpit.getMessageSummary();
192
+ * if (message.Attachments.length) {
193
+ * const thumbnail = await mailpit.getAttachmentThumbnail(message.ID, message.Attachments[0].PartID);
194
+ * // Do something with the thumbnail data
195
+ * }
196
+ * ```
197
+ */
198
+ async getAttachmentThumbnail(id, partID) {
199
+ const response = await this.handleRequest(
200
+ () => this.axiosInstance.get(
201
+ `/api/v1/message/${id}/part/${partID}/thumb`,
202
+ {
203
+ responseType: "arraybuffer"
204
+ }
205
+ ),
206
+ { fullResponse: true }
207
+ );
208
+ return {
209
+ data: response.data,
210
+ contentType: response.headers["content-type"]
211
+ };
212
+ }
213
+ /**
214
+ * Retrieves the full email message source as plain text.
215
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
216
+ * @returns Plain text message source
217
+ * @example
218
+ * ```typescript
219
+ * const messageSource = await mailpit.getMessageSource();
220
+ * ```
221
+ */
222
+ async getMessageSource(id = "latest") {
223
+ return await this.handleRequest(
224
+ () => this.axiosInstance.get(`/api/v1/message/${id}/raw`)
225
+ );
226
+ }
227
+ /**
228
+ * Release a message via a pre-configured external SMTP server.
229
+ * @remarks This is only enabled if message relaying has been configured.
230
+ * @param id - The message database ID. Use `latest` to return the latest message.
231
+ * @param relayTo - Array of email addresses to relay the message to
232
+ * @returns Plain text "ok" response
233
+ * @example
234
+ * ```typescript
235
+ * const message = await mailpit.releaseMessage("latest", ["user1@example.test", "user2@example.test"]);
236
+ * ```
237
+ */
238
+ async releaseMessage(id, relayTo) {
239
+ return await this.handleRequest(
240
+ () => this.axiosInstance.post(`/api/v1/message/${id}/release`, relayTo)
241
+ );
242
+ }
243
+ /**
244
+ * Sends a message
245
+ * @param sendReqest - The request containing the message details.
246
+ * @returns Response containing database messsage ID
247
+ * @example
248
+ * ```typescript
249
+ * await mailpit.sendMessage(
250
+ * From: { Email: "user@example.test", Name: "First LastName" },
251
+ * To: [{ Email: "rec@example.test", Name: "Recipient Name"}, {Email: "another@example.test"}],
252
+ * Subject: "Test Email",
253
+ * );
254
+ * ```
255
+ */
256
+ async sendMessage(sendReqest) {
257
+ return await this.handleRequest(
258
+ () => this.axiosInstance.post(
259
+ `/api/v1/send`,
260
+ sendReqest
261
+ )
262
+ );
263
+ }
264
+ /**
265
+ * Retrieves a list of message summaries ordered from newest to oldest.
266
+ * @remarks Only contains the number of attachments and a snippet of the message body.
267
+ * @see {@link MailpitClient.getMessageSummary | getMessageSummary()} for more attachment and body details for a specific message.
268
+ * @param start - The pagination offset. Defaults to `0`.
269
+ * @param limit - The number of messages to retrieve. Defaults to `50`.
270
+ * @returns A list of message summaries
271
+ * @example
272
+ * ```typescript
273
+ * const messages = await.listMessages();
274
+ * ```
275
+ */
276
+ async listMessages(start = 0, limit = 50) {
277
+ return await this.handleRequest(
278
+ () => this.axiosInstance.get(
279
+ `/api/v1/messages`,
280
+ { params: { start, limit } }
281
+ )
282
+ );
283
+ }
284
+ /**
285
+ * Set the read status of messages.
286
+ * @remarks You can optionally provide an array of `IDs` **OR** a `Search` filter. If neither is set then all messages are updated.
287
+ * @param readStatus - The request containing the message database IDs/search string and the read status.
288
+ * @param readStatus.Read - The read status to set. Defaults to `false`.
289
+ * @param readStatus.IDs - The optional IDs of the messages to update.
290
+ * @param readStatus.Search - The optional search string to filter messages.
291
+ * @param params - Optional parameters for defining the time zone when using the `before:` and `after:` search filters.
292
+ * @see {@link https://mailpit.axllent.org/docs/usage/search-filters/ | Search filters}
293
+ * @returns Plain text "ok" response
294
+ * @example
295
+ * ```typescript
296
+ * // Set all messages as unread
297
+ * await mailpit.setReadStatus();
298
+ *
299
+ * // Set all messages as read
300
+ * await mailpit.setReadStatus({ Read: true });
301
+ *
302
+ * // Set specific messages as read using IDs
303
+ * await mailpit.setReadStatus({ IDs: ["1", "2", "3"], Read: true });
304
+ *
305
+ * // Set specific messages as read using search
306
+ * await mailpit.setReadStatus({ Search: "from:example.test", Read: true });
307
+ *
308
+ * // Set specific messages as read using after: search with time zone
309
+ * await mailpit.setReadStatus({ Search: "after:2025-04-30", Read: true }, { tz: "America/Chicago" });
310
+ * ```
311
+ */
312
+ async setReadStatus(readStatus, params) {
313
+ return await this.handleRequest(
314
+ () => this.axiosInstance.put(`/api/v1/messages`, readStatus, {
315
+ params
316
+ })
317
+ );
318
+ }
319
+ /**
320
+ * Delete individual or all messages.
321
+ * @remarks If no `IDs` are provided then all messages are deleted.
322
+ * @param deleteRequest - The request containing the message database IDs to delete.
323
+ * @returns Plain text "ok" response
324
+ * @example
325
+ * ```typescript
326
+ * // Delete all messages
327
+ * await mailpit.deleteMessages();
328
+ *
329
+ * // Delete specific messages
330
+ * await mailpit.deleteMessages({ IDs: ["1", "2", "3"] });
331
+ * ```
332
+ */
333
+ async deleteMessages(deleteRequest) {
334
+ return await this.handleRequest(
335
+ () => this.axiosInstance.delete(`/api/v1/messages`, {
336
+ data: deleteRequest
337
+ })
338
+ );
339
+ }
340
+ /**
341
+ * Retrieve messages matching a search, sorted by received date (descending).
342
+ * @see {@link https://mailpit.axllent.org/docs/usage/search-filters/ | Search filters}
343
+ * @remarks Only contains the number of attachments and a snippet of the message body.
344
+ * @see {@link MailpitClient.getMessageSummary | getMessageSummary()} for more attachment and body details for a specific message.
345
+ * @param search - The search request containing the query and optional parameters.
346
+ * @returns A list of message summaries matching the search criteria.
347
+ * @example
348
+ * ```typescript
349
+ * // Search for messages from a the domain example.test
350
+ * const messages = await mailpit.searchMessages({query: "from:example.test"});
351
+ * ```
352
+ */
353
+ async searchMessages(search) {
354
+ return await this.handleRequest(
355
+ () => this.axiosInstance.get(`/api/v1/search`, {
356
+ params: search
357
+ })
358
+ );
359
+ }
360
+ /**
361
+ * Delete all messages matching a search.
362
+ * @see {@link https://mailpit.axllent.org/docs/usage/search-filters/ | Search filters}
363
+ * @param search - The search request containing the query.
364
+ * @returns Plain text "ok" response
365
+ * @example
366
+ * ```typescript
367
+ * // Delete all messages from the domain example.test
368
+ * await mailpit.deleteMessagesBySearch({query: "from:example.test"});
369
+ * ```
370
+ */
371
+ async deleteMessagesBySearch(search) {
372
+ return await this.handleRequest(
373
+ () => this.axiosInstance.delete(`/api/v1/search`, { params: search })
374
+ );
375
+ }
376
+ /**
377
+ * Performs an HTML check on a specific message.
378
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
379
+ * @returns The summary of the message HTML checker
380
+ * @example
381
+ * ```typescript
382
+ * const htmlCheck = await mailpit.htmlCheck();
383
+ * ```
384
+ */
385
+ async htmlCheck(id = "latest") {
386
+ return await this.handleRequest(
387
+ () => this.axiosInstance.get(
388
+ `/api/v1/message/${id}/html-check`
389
+ )
390
+ );
391
+ }
392
+ /**
393
+ * Performs a link check on a specific message.
394
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
395
+ * @param follow - Whether to follow links. Defaults to `false`.
396
+ * @returns The summary of the message Link checker.
397
+ * @example
398
+ * ```typescript
399
+ * const linkCheck = await mailpit.linkCheck();
400
+ * ```
401
+ */
402
+ async linkCheck(id = "latest", follow = "false") {
403
+ return await this.handleRequest(
404
+ () => this.axiosInstance.get(
405
+ `/api/v1/message/${id}/link-check`,
406
+ { params: { follow } }
407
+ )
408
+ );
409
+ }
410
+ /**
411
+ * Performs a SpamAssassin check (if enabled) on a specific message.
412
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
413
+ * @returns The SpamAssassin summary (if enabled)
414
+ * @example
415
+ * ```typescript
416
+ * const spamAssassinCheck = await mailpit.spamAssassinCheck();
417
+ * ```
418
+ */
419
+ async spamAssassinCheck(id = "latest") {
420
+ return await this.handleRequest(
421
+ () => this.axiosInstance.get(
422
+ `/api/v1/message/${id}/sa-check`
423
+ )
424
+ );
425
+ }
426
+ /**
427
+ * Retrieves a list of all the unique tags.
428
+ * @returns All unique message tags
429
+ * @example
430
+ * ```typescript
431
+ * const tags = await mailpit.getTags();
432
+ * ```
433
+ */
434
+ async getTags() {
435
+ return await this.handleRequest(
436
+ () => this.axiosInstance.get(`/api/v1/tags`)
437
+ );
438
+ }
439
+ /**
440
+ * Sets and removes tag(s) on message(s). This will overwrite any existing tags for selected message database IDs.
441
+ * @param request - The request containing the message IDs and tags. To remove all tags from a message, pass an empty `Tags` array or exclude `Tags` entirely.
442
+ * @remarks
443
+ * Tags are limited to the following characters: `a-z`, `A-Z`, `0-9`, `-`, `.`, `spaces`, and `_`, and must be a minimum of 1 character.
444
+ * Other characters are silently stripped from the tag.
445
+ * @returns Plain text "ok" response
446
+ * @example
447
+ * ```typescript
448
+ * // Set tags on message(s)
449
+ * await mailpit.setTags({ IDs: ["1", "2", "3"], Tags: ["tag1", "tag2"] });
450
+ * // Remove tags from message(s)
451
+ * await mailpit.setTags({ IDs: ["1", "2", "3"]});
452
+ * ```
453
+ */
454
+ async setTags(request) {
455
+ return await this.handleRequest(
456
+ () => this.axiosInstance.put(`/api/v1/tags`, request)
457
+ );
458
+ }
459
+ /**
460
+ * Renames an existing tag.
461
+ * @param tag - The current name of the tag.
462
+ * @param newTagName - A new name for the tag.
463
+ * @remarks
464
+ * Tags are limited to the following characters: `a-z`, `A-Z`, `0-9`, `-`, `.`, `spaces`, and `_`, and must be a minimum of 1 character.
465
+ * Other characters are silently stripped from the tag.
466
+ * @returns Plain text "ok" response
467
+ * @example
468
+ * ```typescript
469
+ * await mailpit.renameTag("Old Tag Name", "New Tag Name");
470
+ * ```
471
+ */
472
+ async renameTag(tag, newTagName) {
473
+ const encodedTag = encodeURIComponent(tag);
474
+ return await this.handleRequest(
475
+ () => this.axiosInstance.put(`/api/v1/tags/${encodedTag}`, {
476
+ Name: newTagName
477
+ })
478
+ );
479
+ }
480
+ /**
481
+ * Deletes a tag from all messages.
482
+ * @param tag - The name of the tag to delete.
483
+ * @remarks This does NOT delete any messages
484
+ * @returns Plain text "ok" response
485
+ * ```typescript
486
+ * await mailpit.deleteTag("Tag 1");
487
+ * ```
488
+ */
489
+ async deleteTag(tag) {
490
+ const encodedTag = encodeURIComponent(tag);
491
+ return await this.handleRequest(
492
+ () => this.axiosInstance.delete(`/api/v1/tags/${encodedTag}`)
493
+ );
494
+ }
495
+ /**
496
+ * Retrieves the current Chaos triggers configuration (if enabled).
497
+ * @remarks This will return an error if Chaos is not enabled at runtime.
498
+ * @returns The Chaos triggers configuration
499
+ * @example
500
+ * ```typescript
501
+ * const triggers = await mailpit.getChaosTriggers();
502
+ * ```
503
+ */
504
+ async getChaosTriggers() {
505
+ return await this.handleRequest(
506
+ () => this.axiosInstance.get("/api/v1/chaos")
507
+ );
508
+ }
509
+ /**
510
+ * Sets and/or resets the Chaos triggers configuration (if enabled).
511
+ * @param triggers - The request containing the chaos triggers. Omitted triggers will reset to the default `0%` probabibility.
512
+ * @remarks This will return an error if Chaos is not enabled at runtime.
513
+ * @returns The updated Chaos triggers configuration
514
+ * @example
515
+ * ```typescript
516
+ * // Reset all triggers to `0%` probability
517
+ * const triggers = await mailpit.setChaosTriggers();
518
+ * // Set `Sender` and reset `Authentication` and `Recipient` triggers
519
+ * const triggers = await mailpit.setChaosTriggers({ Sender: { ErrorCode: 451, Probability: 5 } });
520
+ * ```
521
+ */
522
+ async setChaosTriggers(triggers = {}) {
523
+ return await this.handleRequest(
524
+ () => this.axiosInstance.put(
525
+ "/api/v1/chaos",
526
+ triggers
527
+ )
528
+ );
529
+ }
530
+ /**
531
+ * Renders the HTML part of a specific message which can be used for UI integration testing.
532
+ * @remarks
533
+ * Attached inline images are modified to link to the API provided they exist.
534
+ * If the message does not contain an HTML part then a 404 error is returned.
535
+ *
536
+ *
537
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
538
+ * @param embed - Whether this route is to be embedded in an iframe. Defaults to `undefined`. Set to `1` to embed.
539
+ * The `embed` parameter will add `target="_blank"` and `rel="noreferrer noopener"` to all links.
540
+ * In addition, a small script will be added to the end of the document to post (postMessage()) the height of the document back to the parent window for optional iframe height resizing.
541
+ * Note that this will also transform the message into a full HTML document (if it isn't already), so this option is useful for viewing but not programmatic testing.
542
+ * @returns Rendered HTML
543
+ * @example
544
+ * ```typescript
545
+ * const html = await mailpit.renderMessageHTML();
546
+ * ```
547
+ */
548
+ async renderMessageHTML(id = "latest", embed) {
549
+ return await this.handleRequest(
550
+ () => this.axiosInstance.get(`/view/${id}.html`, { params: { embed } })
551
+ );
552
+ }
553
+ /**
554
+ * Renders just the message's text part which can be used for UI integration testing.
555
+ * @param id - The message database ID. Defaults to `latest` to return the latest message.
556
+ * @returns Plain text
557
+ * @example
558
+ * ```typescript
559
+ * const html = await mailpit.renderMessageText();
560
+ * ```
561
+ */
562
+ async renderMessageText(id = "latest") {
563
+ return await this.handleRequest(
564
+ () => this.axiosInstance.get(`/view/${id}.txt`)
565
+ );
566
+ }
567
+ };
568
+ // Annotate the CommonJS export names for ESM import in node:
569
+ 0 && (module.exports = {
570
+ MailpitClient
571
+ });