-
-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathmailpit.ts
More file actions
80 lines (71 loc) · 2.58 KB
/
mailpit.ts
File metadata and controls
80 lines (71 loc) · 2.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { MailpitClient } from 'mailpit-api'
export type { MailpitClient }
type Message = Awaited<ReturnType<MailpitClient['getMessageSummary']>>
/** Creates a MailpitClient using MAILPIT_URL (default: http://localhost:8025). */
export function createMailpitClient(): MailpitClient {
return new MailpitClient(process.env.MAILPIT_URL ?? 'http://localhost:8025')
}
/** Fetches the latest email sent to `toAddress`, optionally filtered by `subject`. */
export async function getLatestEmailTo(
client: MailpitClient,
toAddress: string,
subject?: string,
): Promise<Message> {
const query = subject
? `to:${toAddress} subject:"${subject}"`
: `to:${toAddress}`
const result = await client.searchMessages({ query })
if (!result.messages || result.messages.length === 0) {
throw new Error(`No email found for "${toAddress}"${subject ? ` with subject "${subject}"` : ''}`)
}
return await client.getMessageSummary(result.messages[0].ID)
}
/**
* Polls MailPit until an email matching `toAddress` (and optional `subject`) is found,
* or until `timeout` ms elapse. Checks every `interval` ms (defaults: 30 s / 1 s).
*/
export async function waitForEmailTo(
client: MailpitClient,
toAddress: string,
subject?: string,
options?: { timeout?: number; interval?: number },
): Promise<Message> {
const timeout = options?.timeout ?? 30_000
const interval = options?.interval ?? 1_000
const deadline = Date.now() + timeout
while (Date.now() < deadline) {
try {
return await getLatestEmailTo(client, toAddress, subject)
} catch {
// email not arrived yet
}
await new Promise(resolve => setTimeout(resolve, interval))
}
throw new Error(
`Timeout (${timeout} ms) waiting for email to "${toAddress}"${
subject ? ` with subject "${subject}"` : ''
}`,
)
}
/** Extracts a LibreSign sign link from an email body matching /p/sign/{uuid}. */
export function extractSignLink(body: string): string | null {
const match = body.match(/\S+\/p\/sign\/[\w-]+/)
return match ? match[0] : null
}
/** Extracts a numeric token from an email body. Default pattern: 4-8 digit sequence. */
export function extractTokenFromEmail(
body: string,
pattern: RegExp = /Use this code to sign the document:[\s\S]*?(\d{6})/,
): string | null {
const match = body.match(pattern)
return match ? match[1] : null
}
/** Extracts the first URL from an email body (email.Text). */
export function extractLinkFromEmail(body: string): string | null {
const match = body.match(/https?:\/\/\S+/)
return match ? match[0] : null
}