@veloxts/mail 0.6.51

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/GUIDE.md ADDED
@@ -0,0 +1,132 @@
1
+ # @veloxts/mail Guide
2
+
3
+ ## Drivers
4
+
5
+ ### Log Driver (default)
6
+
7
+ Logs emails to console. Best for development.
8
+
9
+ ```typescript
10
+ import { mailPlugin } from '@veloxts/mail';
11
+
12
+ app.use(mailPlugin({ driver: 'log' }));
13
+ ```
14
+
15
+ ### SMTP Driver
16
+
17
+ Send via any SMTP server.
18
+
19
+ ```typescript
20
+ app.use(mailPlugin({
21
+ driver: 'smtp',
22
+ config: {
23
+ host: 'smtp.example.com',
24
+ port: 587,
25
+ secure: false,
26
+ auth: {
27
+ user: process.env.SMTP_USER,
28
+ pass: process.env.SMTP_PASS,
29
+ },
30
+ },
31
+ from: { name: 'My App', email: 'noreply@myapp.com' },
32
+ }));
33
+ ```
34
+
35
+ ### Resend Driver
36
+
37
+ Send via Resend API.
38
+
39
+ ```bash
40
+ npm install resend
41
+ ```
42
+
43
+ ```typescript
44
+ app.use(mailPlugin({
45
+ driver: 'resend',
46
+ config: {
47
+ apiKey: process.env.RESEND_API_KEY,
48
+ },
49
+ from: { name: 'My App', email: 'noreply@myapp.com' },
50
+ }));
51
+ ```
52
+
53
+ ## Defining Email Templates
54
+
55
+ Using React Email components:
56
+
57
+ ```typescript
58
+ import { defineMail } from '@veloxts/mail';
59
+ import { Html, Head, Body, Container, Text, Button } from '@react-email/components';
60
+
61
+ export const WelcomeEmail = defineMail({
62
+ name: 'welcome',
63
+ schema: z.object({
64
+ user: z.object({ name: z.string() }),
65
+ activationUrl: z.string().url(),
66
+ }),
67
+ subject: ({ user }) => `Welcome, ${user.name}!`,
68
+ template: ({ user, activationUrl }) => (
69
+ <Html>
70
+ <Head />
71
+ <Body>
72
+ <Container>
73
+ <Text>Hello {user.name}, welcome to our app!</Text>
74
+ <Button href={activationUrl}>Activate Account</Button>
75
+ </Container>
76
+ </Body>
77
+ </Html>
78
+ ),
79
+ });
80
+ ```
81
+
82
+ ## Sending Emails
83
+
84
+ ```typescript
85
+ // Send immediately
86
+ await ctx.mail.send(WelcomeEmail, {
87
+ to: 'user@example.com',
88
+ data: { user, activationUrl },
89
+ });
90
+
91
+ // With CC/BCC
92
+ await ctx.mail.send(WelcomeEmail, {
93
+ to: 'user@example.com',
94
+ cc: ['manager@example.com'],
95
+ bcc: ['archive@example.com'],
96
+ data: { user, activationUrl },
97
+ });
98
+
99
+ // With attachments
100
+ await ctx.mail.send(InvoiceEmail, {
101
+ to: 'user@example.com',
102
+ data: { invoice },
103
+ attachments: [
104
+ { filename: 'invoice.pdf', content: pdfBuffer },
105
+ ],
106
+ });
107
+ ```
108
+
109
+ ## Bulk Sending
110
+
111
+ ```typescript
112
+ const results = await ctx.mail.sendBulk(WelcomeEmail, [
113
+ { to: 'a@example.com', data: { user: userA, activationUrl: urlA } },
114
+ { to: 'b@example.com', data: { user: userB, activationUrl: urlB } },
115
+ ]);
116
+ ```
117
+
118
+ ## Preview Emails
119
+
120
+ Render without sending (useful for testing):
121
+
122
+ ```typescript
123
+ const { html, text, subject } = await ctx.mail.render(WelcomeEmail, {
124
+ data: { user, activationUrl },
125
+ });
126
+ ```
127
+
128
+ ## CLI Commands
129
+
130
+ ```bash
131
+ velox make mail WelcomeEmail # Generate email template
132
+ ```
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 VeloxTS Framework Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @veloxts/mail
2
+
3
+ > **Early Preview** - APIs may change before v1.0.
4
+
5
+ Email sending with React Email templates and multiple transport drivers.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @veloxts/mail
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { mailPlugin, defineMail } from '@veloxts/mail';
17
+
18
+ app.use(mailPlugin({ driver: 'log' }));
19
+
20
+ const WelcomeEmail = defineMail({
21
+ subject: ({ name }) => `Welcome, ${name}!`,
22
+ template: ({ name }) => <Text>Hello {name}, welcome to our app!</Text>,
23
+ });
24
+
25
+ await ctx.mail.send(WelcomeEmail, { to: 'user@example.com', data: { name: 'John' } });
26
+ ```
27
+
28
+ See [GUIDE.md](./GUIDE.md) for detailed documentation.
29
+
30
+ ## License
31
+
32
+ MIT
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @veloxts/mail
3
+ *
4
+ * Email templating and sending for VeloxTS framework.
5
+ *
6
+ * Features:
7
+ * - React Email integration for type-safe templates
8
+ * - Multiple transport drivers: SMTP, Resend, Log (development)
9
+ * - Type-safe template props with Zod schemas
10
+ * - Automatic plain text generation from HTML
11
+ * - Fastify plugin for request context integration
12
+ * - Bulk email sending
13
+ * - Email preview/rendering without sending
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { mailPlugin, defineMail } from '@veloxts/mail';
18
+ * import { Html, Head, Body, Container, Heading, Text, Button } from '@react-email/components';
19
+ * import { z } from 'zod';
20
+ *
21
+ * // Define a mail template
22
+ * export const WelcomeEmail = defineMail({
23
+ * name: 'welcome',
24
+ * schema: z.object({
25
+ * user: z.object({ name: z.string() }),
26
+ * activationUrl: z.string().url(),
27
+ * }),
28
+ * subject: ({ user }) => `Welcome, ${user.name}!`,
29
+ * template: ({ user, activationUrl }) => (
30
+ * <Html>
31
+ * <Head />
32
+ * <Body>
33
+ * <Container>
34
+ * <Heading>Welcome, {user.name}!</Heading>
35
+ * <Text>Click below to activate your account:</Text>
36
+ * <Button href={activationUrl}>Activate</Button>
37
+ * </Container>
38
+ * </Body>
39
+ * </Html>
40
+ * ),
41
+ * });
42
+ *
43
+ * // Register plugin
44
+ * app.use(mailPlugin({
45
+ * driver: 'resend',
46
+ * config: { apiKey: process.env.RESEND_API_KEY },
47
+ * from: { email: 'hello@myapp.com', name: 'My App' },
48
+ * }));
49
+ *
50
+ * // Send email in procedures
51
+ * await ctx.mail.send(WelcomeEmail, {
52
+ * to: 'user@example.com',
53
+ * data: { user: { name: 'John' }, activationUrl: 'https://...' },
54
+ * });
55
+ * ```
56
+ *
57
+ * @packageDocumentation
58
+ */
59
+ export { defineMail, type MailDefinition, mail } from './mail.js';
60
+ export { createMailManager, type MailManager, mailer, type SendBulkOptions } from './manager.js';
61
+ export { closeMail, getMail, getMailFromInstance, initMail, mailPlugin, } from './plugin.js';
62
+ export { createLogTransport, DRIVER_NAME as LOG_DRIVER } from './transports/log.js';
63
+ export { createResendTransport, DRIVER_NAME as RESEND_DRIVER } from './transports/resend.js';
64
+ export { createSmtpTransport, DRIVER_NAME as SMTP_DRIVER } from './transports/smtp.js';
65
+ export type { Attachment, EmailAddress, LogConfig, MailConfig, MailDefinitionConfig, MailDriver, MailEnvelope, MailPluginOptions, MailTransport, Recipient, RenderedMail, ResendConfig, SendMailOptions, SendResult, SmtpConfig, } from './types.js';
66
+ export { escapeHtml, formatAddress, isValidEmail, normalizeRecipient, normalizeRecipients, sanitizeHeaderValue, stripHtml, validateRecipient, validateRecipients, validateTemplateName, } from './utils.js';
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @veloxts/mail
3
+ *
4
+ * Email templating and sending for VeloxTS framework.
5
+ *
6
+ * Features:
7
+ * - React Email integration for type-safe templates
8
+ * - Multiple transport drivers: SMTP, Resend, Log (development)
9
+ * - Type-safe template props with Zod schemas
10
+ * - Automatic plain text generation from HTML
11
+ * - Fastify plugin for request context integration
12
+ * - Bulk email sending
13
+ * - Email preview/rendering without sending
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { mailPlugin, defineMail } from '@veloxts/mail';
18
+ * import { Html, Head, Body, Container, Heading, Text, Button } from '@react-email/components';
19
+ * import { z } from 'zod';
20
+ *
21
+ * // Define a mail template
22
+ * export const WelcomeEmail = defineMail({
23
+ * name: 'welcome',
24
+ * schema: z.object({
25
+ * user: z.object({ name: z.string() }),
26
+ * activationUrl: z.string().url(),
27
+ * }),
28
+ * subject: ({ user }) => `Welcome, ${user.name}!`,
29
+ * template: ({ user, activationUrl }) => (
30
+ * <Html>
31
+ * <Head />
32
+ * <Body>
33
+ * <Container>
34
+ * <Heading>Welcome, {user.name}!</Heading>
35
+ * <Text>Click below to activate your account:</Text>
36
+ * <Button href={activationUrl}>Activate</Button>
37
+ * </Container>
38
+ * </Body>
39
+ * </Html>
40
+ * ),
41
+ * });
42
+ *
43
+ * // Register plugin
44
+ * app.use(mailPlugin({
45
+ * driver: 'resend',
46
+ * config: { apiKey: process.env.RESEND_API_KEY },
47
+ * from: { email: 'hello@myapp.com', name: 'My App' },
48
+ * }));
49
+ *
50
+ * // Send email in procedures
51
+ * await ctx.mail.send(WelcomeEmail, {
52
+ * to: 'user@example.com',
53
+ * data: { user: { name: 'John' }, activationUrl: 'https://...' },
54
+ * });
55
+ * ```
56
+ *
57
+ * @packageDocumentation
58
+ */
59
+ // Mail definition
60
+ export { defineMail, mail } from './mail.js';
61
+ // Manager
62
+ export { createMailManager, mailer } from './manager.js';
63
+ // Plugin
64
+ export { closeMail, getMail, getMailFromInstance, initMail, mailPlugin, } from './plugin.js';
65
+ // Transports
66
+ export { createLogTransport, DRIVER_NAME as LOG_DRIVER } from './transports/log.js';
67
+ export { createResendTransport, DRIVER_NAME as RESEND_DRIVER } from './transports/resend.js';
68
+ export { createSmtpTransport, DRIVER_NAME as SMTP_DRIVER } from './transports/smtp.js';
69
+ // Utilities
70
+ export { escapeHtml, formatAddress, isValidEmail, normalizeRecipient, normalizeRecipients, sanitizeHeaderValue, stripHtml, validateRecipient, validateRecipients, validateTemplateName, } from './utils.js';
package/dist/mail.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Mail Definition
3
+ *
4
+ * Type-safe email template definitions with React Email.
5
+ */
6
+ import type { z } from 'zod';
7
+ import type { MailDefinition, MailDefinitionConfig } from './types.js';
8
+ /**
9
+ * Define a type-safe email template with React Email.
10
+ *
11
+ * @param config - Mail definition configuration
12
+ * @returns Mail definition
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { defineMail } from '@veloxts/mail';
17
+ * import { Html, Head, Body, Container, Heading, Text, Button } from '@react-email/components';
18
+ * import { z } from 'zod';
19
+ *
20
+ * export const WelcomeEmail = defineMail({
21
+ * name: 'welcome',
22
+ * schema: z.object({
23
+ * user: z.object({ name: z.string(), email: z.string() }),
24
+ * activationUrl: z.string().url(),
25
+ * }),
26
+ * subject: ({ user }) => `Welcome to our app, ${user.name}!`,
27
+ * template: ({ user, activationUrl }) => (
28
+ * <Html>
29
+ * <Head />
30
+ * <Body>
31
+ * <Container>
32
+ * <Heading>Welcome, {user.name}!</Heading>
33
+ * <Text>Click below to activate your account:</Text>
34
+ * <Button href={activationUrl}>Activate Account</Button>
35
+ * </Container>
36
+ * </Body>
37
+ * </Html>
38
+ * ),
39
+ * });
40
+ * ```
41
+ */
42
+ export declare function defineMail<TSchema extends z.ZodType>(config: MailDefinitionConfig<TSchema>): MailDefinition<TSchema>;
43
+ /**
44
+ * Alias for defineMail.
45
+ */
46
+ export declare const mail: typeof defineMail;
47
+ export type { MailDefinition } from './types.js';
package/dist/mail.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Mail Definition
3
+ *
4
+ * Type-safe email template definitions with React Email.
5
+ */
6
+ import { validateTemplateName } from './utils.js';
7
+ /**
8
+ * Define a type-safe email template with React Email.
9
+ *
10
+ * @param config - Mail definition configuration
11
+ * @returns Mail definition
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { defineMail } from '@veloxts/mail';
16
+ * import { Html, Head, Body, Container, Heading, Text, Button } from '@react-email/components';
17
+ * import { z } from 'zod';
18
+ *
19
+ * export const WelcomeEmail = defineMail({
20
+ * name: 'welcome',
21
+ * schema: z.object({
22
+ * user: z.object({ name: z.string(), email: z.string() }),
23
+ * activationUrl: z.string().url(),
24
+ * }),
25
+ * subject: ({ user }) => `Welcome to our app, ${user.name}!`,
26
+ * template: ({ user, activationUrl }) => (
27
+ * <Html>
28
+ * <Head />
29
+ * <Body>
30
+ * <Container>
31
+ * <Heading>Welcome, {user.name}!</Heading>
32
+ * <Text>Click below to activate your account:</Text>
33
+ * <Button href={activationUrl}>Activate Account</Button>
34
+ * </Container>
35
+ * </Body>
36
+ * </Html>
37
+ * ),
38
+ * });
39
+ * ```
40
+ */
41
+ export function defineMail(config) {
42
+ validateTemplateName(config.name);
43
+ return {
44
+ name: config.name,
45
+ schema: config.schema,
46
+ subject: config.subject,
47
+ template: config.template,
48
+ text: config.text,
49
+ from: config.from,
50
+ };
51
+ }
52
+ /**
53
+ * Alias for defineMail.
54
+ */
55
+ export const mail = defineMail;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Mail Manager
3
+ *
4
+ * High-level mail API for rendering and sending emails.
5
+ */
6
+ import type { z } from 'zod';
7
+ import type { MailDefinition } from './mail.js';
8
+ import type { MailPluginOptions, RenderedMail, SendMailOptions, SendResult } from './types.js';
9
+ /**
10
+ * Mail manager interface.
11
+ */
12
+ /**
13
+ * Options for bulk email sending.
14
+ */
15
+ export interface SendBulkOptions {
16
+ /**
17
+ * Maximum number of concurrent email sends.
18
+ * Higher values = faster but more memory/CPU.
19
+ * @default 10
20
+ */
21
+ concurrency?: number;
22
+ }
23
+ export interface MailManager {
24
+ /**
25
+ * Send an email using a mail definition.
26
+ */
27
+ send<TSchema extends z.ZodType>(mail: MailDefinition<TSchema>, options: SendMailOptions<TSchema>): Promise<SendResult>;
28
+ /**
29
+ * Send an email to multiple recipients with different data.
30
+ * Uses parallel execution with configurable concurrency control.
31
+ */
32
+ sendBulk<TSchema extends z.ZodType>(mail: MailDefinition<TSchema>, messages: Array<SendMailOptions<TSchema>>, options?: SendBulkOptions): Promise<SendResult[]>;
33
+ /**
34
+ * Render an email without sending (for preview/testing).
35
+ */
36
+ render<TSchema extends z.ZodType>(mail: MailDefinition<TSchema>, options: SendMailOptions<TSchema>): Promise<RenderedMail>;
37
+ /**
38
+ * Close the transport connection.
39
+ */
40
+ close(): Promise<void>;
41
+ }
42
+ /**
43
+ * Create a mail manager.
44
+ *
45
+ * @param options - Mail plugin options
46
+ * @returns Mail manager instance
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * // Development (log to console)
51
+ * const mail = await createMailManager({ driver: 'log' });
52
+ *
53
+ * // Production (SMTP)
54
+ * const mail = await createMailManager({
55
+ * driver: 'smtp',
56
+ * config: {
57
+ * host: 'smtp.example.com',
58
+ * port: 587,
59
+ * auth: { user: '...', pass: '...' },
60
+ * },
61
+ * from: { email: 'hello@example.com', name: 'My App' },
62
+ * });
63
+ *
64
+ * // Production (Resend)
65
+ * const mail = await createMailManager({
66
+ * driver: 'resend',
67
+ * config: { apiKey: process.env.RESEND_API_KEY! },
68
+ * from: { email: 'hello@example.com', name: 'My App' },
69
+ * });
70
+ *
71
+ * // Send email
72
+ * await mail.send(WelcomeEmail, {
73
+ * to: 'user@example.com',
74
+ * data: { user: { name: 'John' }, activationUrl: 'https://...' },
75
+ * });
76
+ * ```
77
+ */
78
+ export declare function createMailManager(options?: MailPluginOptions): Promise<MailManager>;
79
+ /**
80
+ * Alias for createMailManager.
81
+ */
82
+ export declare const mailer: typeof createMailManager;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Mail Manager
3
+ *
4
+ * High-level mail API for rendering and sending emails.
5
+ */
6
+ import { render } from '@react-email/render';
7
+ import { createLogTransport } from './transports/log.js';
8
+ import { createResendTransport } from './transports/resend.js';
9
+ import { createSmtpTransport } from './transports/smtp.js';
10
+ import { normalizeRecipient, normalizeRecipients, stripHtml, validateRecipients } from './utils.js';
11
+ /**
12
+ * Create a mail manager.
13
+ *
14
+ * @param options - Mail plugin options
15
+ * @returns Mail manager instance
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Development (log to console)
20
+ * const mail = await createMailManager({ driver: 'log' });
21
+ *
22
+ * // Production (SMTP)
23
+ * const mail = await createMailManager({
24
+ * driver: 'smtp',
25
+ * config: {
26
+ * host: 'smtp.example.com',
27
+ * port: 587,
28
+ * auth: { user: '...', pass: '...' },
29
+ * },
30
+ * from: { email: 'hello@example.com', name: 'My App' },
31
+ * });
32
+ *
33
+ * // Production (Resend)
34
+ * const mail = await createMailManager({
35
+ * driver: 'resend',
36
+ * config: { apiKey: process.env.RESEND_API_KEY! },
37
+ * from: { email: 'hello@example.com', name: 'My App' },
38
+ * });
39
+ *
40
+ * // Send email
41
+ * await mail.send(WelcomeEmail, {
42
+ * to: 'user@example.com',
43
+ * data: { user: { name: 'John' }, activationUrl: 'https://...' },
44
+ * });
45
+ * ```
46
+ */
47
+ export async function createMailManager(options = {}) {
48
+ const defaultFrom = options.from ? normalizeRecipient(options.from) : undefined;
49
+ const defaultReplyTo = options.replyTo ? normalizeRecipient(options.replyTo) : undefined;
50
+ let transport;
51
+ // Create the appropriate transport with type-safe config narrowing
52
+ if (options.driver === 'smtp') {
53
+ // Type narrows: options.config is SmtpConfig (required)
54
+ transport = await createSmtpTransport(options.config);
55
+ }
56
+ else if (options.driver === 'resend') {
57
+ // Type narrows: options.config is ResendConfig (required)
58
+ transport = await createResendTransport(options.config);
59
+ }
60
+ else {
61
+ // Type narrows: options.config is LogConfig | undefined (driver is 'log' or undefined)
62
+ transport = createLogTransport(options.config);
63
+ }
64
+ /**
65
+ * Render a mail template to HTML.
66
+ */
67
+ async function renderMail(mail, sendOptions) {
68
+ // Validate data against schema
69
+ const validatedData = mail.schema.parse(sendOptions.data);
70
+ // Validate recipients
71
+ validateRecipients(sendOptions.to);
72
+ // Determine from address
73
+ const from = sendOptions.from
74
+ ? normalizeRecipient(sendOptions.from)
75
+ : mail.from
76
+ ? normalizeRecipient(mail.from)
77
+ : defaultFrom;
78
+ if (!from) {
79
+ throw new Error('From address is required. Provide it in send options, mail definition, or plugin config.');
80
+ }
81
+ // Normalize recipients
82
+ const to = normalizeRecipients(sendOptions.to);
83
+ const cc = sendOptions.cc ? normalizeRecipients(sendOptions.cc) : undefined;
84
+ const bcc = sendOptions.bcc ? normalizeRecipients(sendOptions.bcc) : undefined;
85
+ const replyTo = sendOptions.replyTo ? normalizeRecipient(sendOptions.replyTo) : defaultReplyTo;
86
+ // Generate subject
87
+ const subject = typeof mail.subject === 'function' ? mail.subject(validatedData) : mail.subject;
88
+ // Render React Email template to HTML
89
+ const html = await render(mail.template(validatedData));
90
+ // Generate plain text (from custom function or by stripping HTML)
91
+ const text = mail.text ? mail.text(validatedData) : stripHtml(html);
92
+ return {
93
+ from,
94
+ to,
95
+ cc,
96
+ bcc,
97
+ replyTo,
98
+ subject,
99
+ html,
100
+ text,
101
+ attachments: sendOptions.attachments,
102
+ headers: sendOptions.headers,
103
+ tags: sendOptions.tags,
104
+ };
105
+ }
106
+ const manager = {
107
+ async send(mail, sendOptions) {
108
+ const rendered = await renderMail(mail, sendOptions);
109
+ return transport.send({
110
+ from: rendered.from,
111
+ to: rendered.to,
112
+ cc: rendered.cc,
113
+ bcc: rendered.bcc,
114
+ replyTo: rendered.replyTo,
115
+ subject: rendered.subject,
116
+ html: rendered.html,
117
+ text: rendered.text,
118
+ attachments: rendered.attachments,
119
+ headers: rendered.headers,
120
+ tags: rendered.tags,
121
+ });
122
+ },
123
+ async sendBulk(mail, messages, bulkOptions) {
124
+ if (messages.length === 0) {
125
+ return [];
126
+ }
127
+ // Use concurrency control to avoid overwhelming the transport
128
+ const concurrency = bulkOptions?.concurrency ?? 10;
129
+ // Process in batches for controlled parallelism
130
+ const results = new Array(messages.length);
131
+ for (let i = 0; i < messages.length; i += concurrency) {
132
+ const batch = messages.slice(i, i + concurrency);
133
+ const batchResults = await Promise.all(batch.map((message) => manager.send(mail, message)));
134
+ // Place results at correct indices to maintain order
135
+ for (let j = 0; j < batchResults.length; j++) {
136
+ results[i + j] = batchResults[j];
137
+ }
138
+ }
139
+ return results;
140
+ },
141
+ async render(mail, sendOptions) {
142
+ return renderMail(mail, sendOptions);
143
+ },
144
+ async close() {
145
+ await transport.close();
146
+ },
147
+ };
148
+ return manager;
149
+ }
150
+ /**
151
+ * Alias for createMailManager.
152
+ */
153
+ export const mailer = createMailManager;