@workermailer/smtp 0.1.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.
@@ -0,0 +1,93 @@
1
+ import { d as WorkerMailerOptions, b as EmailOptions } from './mailer-CNOSp-w6.js';
2
+
3
+ /**
4
+ * Message format for the email queue
5
+ */
6
+ type QueueEmailMessage = {
7
+ mailerOptions: WorkerMailerOptions;
8
+ emailOptions: EmailOptions;
9
+ };
10
+ /**
11
+ * Result of processing a queued email
12
+ */
13
+ type QueueProcessResult = {
14
+ success: boolean;
15
+ error?: string;
16
+ emailOptions: EmailOptions;
17
+ };
18
+ /**
19
+ * Creates a queue handler for processing emails asynchronously via Cloudflare Queues.
20
+ *
21
+ * This is useful for:
22
+ * - Offloading email sending from the main request
23
+ * - Handling email sending with automatic retries (via Queue retry policies)
24
+ * - Processing emails in batches
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // In your worker:
29
+ * import { createQueueHandler } from '@ribassu/worker-mailer/queue'
30
+ *
31
+ * export default {
32
+ * async queue(batch, env, ctx) {
33
+ * const handler = createQueueHandler()
34
+ * const results = await handler(batch)
35
+ * console.log('Processed emails:', results)
36
+ * }
37
+ * }
38
+ *
39
+ * // To enqueue an email:
40
+ * await env.EMAIL_QUEUE.send({
41
+ * mailerOptions: {
42
+ * host: 'smtp.example.com',
43
+ * port: 587,
44
+ * credentials: { username: 'user', password: 'pass' },
45
+ * authType: 'plain'
46
+ * },
47
+ * emailOptions: {
48
+ * from: 'sender@example.com',
49
+ * to: 'recipient@example.com',
50
+ * subject: 'Hello',
51
+ * text: 'World'
52
+ * }
53
+ * })
54
+ * ```
55
+ *
56
+ * @param onSuccess - Optional callback when email is sent successfully
57
+ * @param onError - Optional callback when email fails to send
58
+ * @returns A queue handler function
59
+ */
60
+ declare function createQueueHandler(options?: {
61
+ onSuccess?: (result: QueueProcessResult) => void | Promise<void>;
62
+ onError?: (result: QueueProcessResult) => void | Promise<void>;
63
+ }): (batch: MessageBatch<QueueEmailMessage>) => Promise<QueueProcessResult[]>;
64
+ /**
65
+ * Helper to enqueue an email for async processing.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * import { enqueueEmail } from '@ribassu/worker-mailer/queue'
70
+ *
71
+ * await enqueueEmail(env.EMAIL_QUEUE, {
72
+ * mailerOptions: { host: 'smtp.example.com', port: 587, ... },
73
+ * emailOptions: { from: '...', to: '...', subject: '...', text: '...' }
74
+ * })
75
+ * ```
76
+ */
77
+ declare function enqueueEmail(queue: Queue<QueueEmailMessage>, message: QueueEmailMessage): Promise<void>;
78
+ /**
79
+ * Helper to enqueue multiple emails for async processing.
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * import { enqueueEmails } from '@ribassu/worker-mailer/queue'
84
+ *
85
+ * await enqueueEmails(env.EMAIL_QUEUE, [
86
+ * { mailerOptions: {...}, emailOptions: {...} },
87
+ * { mailerOptions: {...}, emailOptions: {...} },
88
+ * ])
89
+ * ```
90
+ */
91
+ declare function enqueueEmails(queue: Queue<QueueEmailMessage>, messages: QueueEmailMessage[]): Promise<void>;
92
+
93
+ export { type QueueEmailMessage, type QueueProcessResult, createQueueHandler, enqueueEmail, enqueueEmails };
package/dist/queue.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";var $=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var W=(r,e)=>{for(var t in e)$(r,t,{get:e[t],enumerable:!0})},N=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of M(e))!k.call(r,s)&&s!==t&&$(r,s,{get:()=>e[s],enumerable:!(i=D(e,s))||i.enumerable});return r};var P=r=>N($({},"__esModule",{value:!0}),r);var q={};W(q,{createQueueHandler:()=>j,enqueueEmail:()=>Y,enqueueEmails:()=>Q});module.exports=P(q);var F=require("cloudflare:sockets");var S=class{values=[];resolvers=[];enqueue(e){this.resolvers.length||this.addWrapper(),this.resolvers.shift()(e)}async dequeue(){return this.values.length||this.addWrapper(),this.values.shift()}get length(){return this.values.length}clear(){this.values=[],this.resolvers=[]}addWrapper(){this.values.push(new Promise(e=>{this.resolvers.push(e)}))}};function m(r){if(!r||typeof r!="string"||!/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(r))return!1;let[t,i]=r.split("@");if(t.length>64||i.length>255||!i.includes("."))return!1;let s=i.split(".").pop();return!(!s||s.length<2)}async function L(r,e,t){return Promise.race([r,new Promise((i,s)=>setTimeout(()=>s(t),e))])}var H=new TextEncoder;function p(r){return H.encode(r)}var B=new TextDecoder("utf-8");function I(r){return B.decode(r)}function U(r,e=76){let t=p(r),i="",s=0,o=0;for(;o<t.length;){let h=t[o],l;if(h===10){i+=`\r
2
+ `,s=0,o++;continue}else if(h===13)if(o+1<t.length&&t[o+1]===10){i+=`\r
3
+ `,s=0,o+=2;continue}else l="=0D";if(l===void 0){let d=h===32||h===9,f=o+1>=t.length||t[o+1]===10||t[o+1]===13;h<32&&!d||h>126||h===61||d&&f?l=`=${h.toString(16).toUpperCase().padStart(2,"0")}`:l=String.fromCharCode(h)}s+l.length>e-3&&(i+=`=\r
4
+ `,s=0),i+=l,s+=l.length,o++}return i}var u=class extends Error{code;constructor(e,t){super(e),this.name="WorkerMailerError",this.code=t}},b=class extends u{invalidEmails;constructor(e,t=[]){super(e,"INVALID_EMAIL"),this.name="InvalidEmailError",this.invalidEmails=t}},c=class extends u{constructor(e){super(e,"AUTH_FAILED"),this.name="SmtpAuthError"}},A=class extends u{constructor(e){super(e,"CONNECTION_FAILED"),this.name="SmtpConnectionError"}},O=class extends u{recipient;constructor(e,t){super(e,"RECIPIENT_REJECTED"),this.name="SmtpRecipientError",this.recipient=t}},w=class extends u{constructor(e){super(e,"TIMEOUT"),this.name="SmtpTimeoutError"}},C=class extends u{constructor(e){super(e,"INVALID_CONTENT"),this.name="InvalidContentError"}};function g(r){if(!/[^\x00-\x7F]/.test(r))return r;let e=p(r),t="";for(let i of e)i>=33&&i<=126&&i!==63&&i!==61&&i!==95?t+=String.fromCharCode(i):i===32?t+="_":t+=`=${i.toString(16).toUpperCase().padStart(2,"0")}`;return`=?UTF-8?Q?${t}?=`}var x=class r{from;to;reply;cc;bcc;subject;text;html;dsnOverride;attachments;headers;setSent;setSentError;sent=new Promise((e,t)=>{this.setSent=e,this.setSentError=t});constructor(e){if(!e.text&&!e.html)throw new C("At least one of text or html must be provided");typeof e.from=="string"?this.from={email:e.from}:this.from=e.from,typeof e.reply=="string"?this.reply={email:e.reply}:this.reply=e.reply,this.to=r.toUsers(e.to),this.cc=r.toUsers(e.cc),this.bcc=r.toUsers(e.bcc),this.validateEmails(),this.subject=e.subject,this.text=e.text,this.html=e.html,this.attachments=e.attachments,this.dsnOverride=e.dsnOverride,this.headers=e.headers||{}}static toUsers(e){if(e)return typeof e=="string"?[{email:e}]:Array.isArray(e)?e.map(t=>typeof t=="string"?{email:t}:t):[e]}validateEmails(){let e=[];m(this.from.email)||e.push(this.from.email);for(let t of this.to)m(t.email)||e.push(t.email);if(this.reply&&!m(this.reply.email)&&e.push(this.reply.email),this.cc)for(let t of this.cc)m(t.email)||e.push(t.email);if(this.bcc)for(let t of this.bcc)m(t.email)||e.push(t.email);if(e.length>0)throw new b(`Invalid email address(es): ${e.join(", ")}`,e)}getEmailData(){this.resolveHeader();let e=["MIME-Version: 1.0"];for(let[a,y]of Object.entries(this.headers))e.push(`${a}: ${y}`);let t=this.generateSafeBoundary("mixed_"),i=this.generateSafeBoundary("related_"),s=this.generateSafeBoundary("alternative_"),o=this.attachments?.filter(a=>a.cid)||[],h=this.attachments?.filter(a=>!a.cid)||[],l=o.length>0,d=h.length>0;e.push(`Content-Type: multipart/mixed; boundary="${t}"`);let n=`${e.join(`\r
5
+ `)}\r
6
+ \r
7
+ `;if(n+=`--${t}\r
8
+ `,l&&(n+=`Content-Type: multipart/related; boundary="${i}"\r
9
+ \r
10
+ `,n+=`--${i}\r
11
+ `),n+=`Content-Type: multipart/alternative; boundary="${s}"\r
12
+ \r
13
+ `,this.text){n+=`--${s}\r
14
+ `,n+=`Content-Type: text/plain; charset="UTF-8"\r
15
+ `,n+=`Content-Transfer-Encoding: quoted-printable\r
16
+ \r
17
+ `;let a=U(this.text);n+=`${a}\r
18
+ \r
19
+ `}if(this.html){n+=`--${s}\r
20
+ `,n+=`Content-Type: text/html; charset="UTF-8"\r
21
+ `,n+=`Content-Transfer-Encoding: quoted-printable\r
22
+ \r
23
+ `;let a=U(this.html);n+=`${a}\r
24
+ \r
25
+ `}if(n+=`--${s}--\r
26
+ `,l){for(let a of o){let y=a.mimeType||this.getMimeType(a.filename);n+=`--${i}\r
27
+ `,n+=`Content-Type: ${y}; name="${a.filename}"\r
28
+ `,n+=`Content-Transfer-Encoding: base64\r
29
+ `,n+=`Content-ID: <${a.cid}>\r
30
+ `,n+=`Content-Disposition: inline; filename="${a.filename}"\r
31
+ \r
32
+ `;let T=a.content.match(/.{1,72}/g);T?n+=`${T.join(`\r
33
+ `)}`:n+=`${a.content}`,n+=`\r
34
+ \r
35
+ `}n+=`--${i}--\r
36
+ `}if(d)for(let a of h){let y=a.mimeType||this.getMimeType(a.filename);n+=`--${t}\r
37
+ `,n+=`Content-Type: ${y}; name="${a.filename}"\r
38
+ `,n+=`Content-Description: ${a.filename}\r
39
+ `,n+=`Content-Disposition: attachment; filename="${a.filename}";\r
40
+ `,n+=` creation-date="${new Date().toUTCString()}";\r
41
+ `,n+=`Content-Transfer-Encoding: base64\r
42
+ \r
43
+ `;let T=a.content.match(/.{1,72}/g);T?n+=`${T.join(`\r
44
+ `)}`:n+=`${a.content}`,n+=`\r
45
+ \r
46
+ `}return n+=`--${t}--\r
47
+ `,`${this.applyDotStuffing(n)}\r
48
+ .\r
49
+ `}applyDotStuffing(e){let t=e.replace(/\r\n\./g,`\r
50
+ ..`);return t.startsWith(".")&&(t=`.${t}`),t}generateSafeBoundary(e){let t=new Uint8Array(28);crypto.getRandomValues(t);let i=Array.from(t).map(o=>o.toString(16).padStart(2,"0")).join(""),s=e+i;return s=s.replace(/[<>@,;:\\/[\]?=" ]/g,"_"),s}getMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{txt:"text/plain",html:"text/html",csv:"text/csv",pdf:"application/pdf",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",zip:"application/zip"}[t||"txt"]||"application/octet-stream"}resolveHeader(){this.resolveFrom(),this.resolveTo(),this.resolveReply(),this.resolveCC(),this.resolveBCC(),this.resolveSubject(),this.headers.Date=this.headers.Date??new Date().toUTCString(),this.headers["Message-ID"]=this.headers["Message-ID"]??`<${crypto.randomUUID()}@${this.from.email.split("@").pop()}>`}resolveFrom(){if(this.headers.From)return;let e=this.from.email;this.from.name&&(e=`"${g(this.from.name)}" <${e}>`),this.headers.From=e}resolveTo(){if(this.headers.To)return;let e=this.to.map(t=>t.name?`"${g(t.name)}" <${t.email}>`:t.email);this.headers.To=e.join(", ")}resolveSubject(){this.headers.Subject||this.subject&&(this.headers.Subject=g(this.subject))}resolveReply(){if(!this.headers["Reply-To"]&&this.reply){let e=this.reply.email;this.reply.name&&(e=`"${g(this.reply.name)}" <${e}>`),this.headers["Reply-To"]=e}}resolveCC(){if(!this.headers.CC&&this.cc){let e=this.cc.map(t=>t.name?`"${g(t.name)}" <${t.email}>`:t.email);this.headers.CC=e.join(", ")}}resolveBCC(){if(!this.headers.BCC&&this.bcc){let e=this.bcc.map(t=>t.name?`"${g(t.name)}" <${t.email}>`:t.email);this.headers.BCC=e.join(", ")}}};var E=class{constructor(e=1,t){this.level=e;this.prefix=t}level;prefix;debug(e,...t){this.level<=0&&console.debug(this.prefix+e,...t)}info(e,...t){this.level<=1&&console.info(this.prefix+e,...t)}warn(e,...t){this.level<=2&&console.warn(this.prefix+e,...t)}error(e,...t){this.level<=3&&console.error(this.prefix+e,...t)}};var R=class r{socket;host;port;secure;startTls;authType;credentials;socketTimeoutMs;responseTimeoutMs;reader;writer;logger;dsn;sendNotificationsTo;hooks;active=!1;emailSending=null;emailSendingOptions=null;emailToBeSent=new S;supportsDSN=!1;allowAuth=!1;authTypeSupported=[];supportsStartTls=!1;constructor(e){this.port=e.port,this.host=e.host,this.secure=!!e.secure,Array.isArray(e.authType)?this.authType=e.authType:typeof e.authType=="string"?this.authType=[e.authType]:this.authType=[],this.startTls=e.startTls===void 0?!0:e.startTls,this.credentials=e.credentials,this.dsn=e.dsn||{},this.hooks=e.hooks||{},this.socketTimeoutMs=e.socketTimeoutMs||6e4,this.responseTimeoutMs=e.responseTimeoutMs||3e4,this.socket=(0,F.connect)({hostname:this.host,port:this.port},{secureTransport:this.secure?"on":this.startTls?"starttls":"off",allowHalfOpen:!1}),this.reader=this.socket.readable.getReader(),this.writer=this.socket.writable.getWriter(),this.logger=new E(e.logLevel,`[WorkerMailer:${this.host}:${this.port}]`)}static async connect(e){let t=new r(e);return await t.initializeSmtpSession(),t.start().catch(console.error),t}send(e){let t=new x(e);return this.emailToBeSent.enqueue({email:t,options:e}),t.sent}static async send(e,t){let i=await r.connect(e);await i.send(t),await i.close()}async readTimeout(){return L(this.read(),this.responseTimeoutMs,new w("Timeout while waiting for smtp server response"))}async read(){let e="";for(;;){let{value:t}=await this.reader.read();if(!t)continue;let i=I(t).toString();if(this.logger.debug(`SMTP server response:
51
+ `+i),e=e+i,!e.endsWith(`
52
+ `))continue;let s=e.split(/\r?\n/),o=s[s.length-2];if(!/^\d+-/.test(o))return e}}async writeLine(e){await this.write(`${e}\r
53
+ `)}async write(e){this.logger.debug(`Write to socket:
54
+ `+e),await this.writer.write(p(e))}async initializeSmtpSession(){await this.waitForSocketConnected(),await this.greet(),await this.ehlo(),this.startTls&&!this.secure&&this.supportsStartTls&&(await this.tls(),await this.ehlo()),await this.auth(),this.active=!0,await this.hooks.onConnect?.()}async start(){for(;this.active;){let{email:e,options:t}=await this.emailToBeSent.dequeue();this.emailSending=e,this.emailSendingOptions=t;try{await this.mail(),await this.rcpt(),await this.data();let i=await this.body();this.emailSending.setSent(),await this.hooks.onSent?.(t,i)}catch(i){if(this.logger.error("Failed to send email: "+i.message),!this.active)return;this.emailSending.setSentError(i),await this.hooks.onError?.(t,i);try{await this.rset()}catch(s){await this.close(s)}}this.emailSending=null,this.emailSendingOptions=null}}async close(e){for(this.active=!1,this.logger.info("WorkerMailer is closed",e?.message||""),this.emailSending?.setSentError?.(e||new Error("WorkerMailer is shutting down"));this.emailToBeSent.length;){let{email:t}=await this.emailToBeSent.dequeue();t.setSentError(e||new Error("WorkerMailer is shutting down"))}try{await this.writeLine("QUIT"),await this.readTimeout(),this.socket.close().catch(()=>this.logger.error("Failed to close socket"))}catch{}await this.hooks.onClose?.(e)}async waitForSocketConnected(){this.logger.info("Connecting to SMTP server"),await L(this.socket.opened,this.socketTimeoutMs,new w("Socket timeout!")),this.logger.info("SMTP server connected")}async greet(){let e=await this.readTimeout();if(!e.startsWith("220"))throw new A("Failed to connect to SMTP server: "+e)}async ehlo(){await this.writeLine("EHLO 127.0.0.1");let e=await this.readTimeout();if(e.startsWith("421"))throw new Error(`Failed to EHLO. ${e}`);if(!e.startsWith("2")){await this.helo();return}this.parseCapabilities(e)}async helo(){await this.writeLine("HELO 127.0.0.1");let e=await this.readTimeout();if(!e.startsWith("2"))throw new Error(`Failed to HELO. ${e}`)}async tls(){await this.writeLine("STARTTLS");let e=await this.readTimeout();if(!e.startsWith("220"))throw new Error("Failed to start TLS: "+e);this.reader.releaseLock(),this.writer.releaseLock(),this.socket=this.socket.startTls(),this.reader=this.socket.readable.getReader(),this.writer=this.socket.writable.getWriter()}parseCapabilities(e){/[ -]AUTH\b/i.test(e)&&(this.allowAuth=!0),/[ -]AUTH(?:(\s+|=)[^\n]*\s+|\s+|=)PLAIN/i.test(e)&&this.authTypeSupported.push("plain"),/[ -]AUTH(?:(\s+|=)[^\n]*\s+|\s+|=)LOGIN/i.test(e)&&this.authTypeSupported.push("login"),/[ -]AUTH(?:(\s+|=)[^\n]*\s+|\s+|=)CRAM-MD5/i.test(e)&&this.authTypeSupported.push("cram-md5"),/[ -]STARTTLS\b/i.test(e)&&(this.supportsStartTls=!0),/[ -]DSN\b/i.test(e)&&(this.supportsDSN=!0)}async auth(){if(this.allowAuth){if(!this.credentials)throw new c("smtp server requires authentication, but no credentials found");if(this.authTypeSupported.includes("plain")&&this.authType.includes("plain"))await this.authWithPlain();else if(this.authTypeSupported.includes("login")&&this.authType.includes("login"))await this.authWithLogin();else if(this.authTypeSupported.includes("cram-md5")&&this.authType.includes("cram-md5"))await this.authWithCramMD5();else throw new c("No supported auth method found.")}}async authWithPlain(){let e=btoa(`\0${this.credentials.username}\0${this.credentials.password}`);await this.writeLine(`AUTH PLAIN ${e}`);let t=await this.readTimeout();if(!t.startsWith("2"))throw new c(`Failed to plain authentication: ${t}`)}async authWithLogin(){await this.writeLine("AUTH LOGIN");let e=await this.readTimeout();if(!e.startsWith("3"))throw new c("Invalid login: "+e);let t=btoa(this.credentials.username);await this.writeLine(t);let i=await this.readTimeout();if(!i.startsWith("3"))throw new c("Failed to login authentication: "+i);let s=btoa(this.credentials.password);await this.writeLine(s);let o=await this.readTimeout();if(!o.startsWith("2"))throw new c("Failed to login authentication: "+o)}async authWithCramMD5(){await this.writeLine("AUTH CRAM-MD5");let e=await this.readTimeout(),t=e.match(/^334\s+(.+)$/)?.pop();if(!t)throw new c("Invalid CRAM-MD5 challenge: "+e);let i=atob(t),s=p(this.credentials.password),o=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"MD5"},!1,["sign"]),h=p(i),l=await crypto.subtle.sign("HMAC",o,h),d=Array.from(new Uint8Array(l)).map(n=>n.toString(16).padStart(2,"0")).join("");await this.writeLine(btoa(`${this.credentials.username} ${d}`));let f=await this.readTimeout();if(!f.startsWith("2"))throw new c("Failed to cram-md5 authentication: "+f)}async mail(){let e=`MAIL FROM: <${this.emailSending.from.email}>`;this.supportsDSN&&(e+=` ${this.retBuilder()}`,this.emailSending?.dsnOverride?.envelopeId&&(e+=` ENVID=${this.emailSending?.dsnOverride?.envelopeId}`)),await this.writeLine(e);let t=await this.readTimeout();if(!t.startsWith("2"))throw new Error(`Invalid ${e} ${t}`)}async rcpt(){let e=[...this.emailSending.to,...this.emailSending.cc||[],...this.emailSending.bcc||[]];for(let t of e){let i=`RCPT TO: <${t.email}>`;this.supportsDSN&&(i+=this.notificationBuilder()),await this.writeLine(i);let s=await this.readTimeout();if(!s.startsWith("2"))throw new O(`Invalid ${i} ${s}`,t.email)}}async data(){await this.writeLine("DATA");let e=await this.readTimeout();if(!e.startsWith("3"))throw new Error(`Failed to send DATA: ${e}`)}async body(){await this.write(this.emailSending.getEmailData());let e=await this.readTimeout();if(!e.startsWith("2"))throw new Error("Failed send email body: "+e);return e}async rset(){await this.writeLine("RSET");let e=await this.readTimeout();if(!e.startsWith("2"))throw new Error(`Failed to reset: ${e}`)}notificationBuilder(){let e=[];return(this.emailSending?.dsnOverride?.NOTIFY&&this.emailSending?.dsnOverride?.NOTIFY?.SUCCESS||!this.emailSending?.dsnOverride?.NOTIFY&&this.dsn?.NOTIFY?.SUCCESS)&&e.push("SUCCESS"),(this.emailSending?.dsnOverride?.NOTIFY&&this.emailSending?.dsnOverride?.NOTIFY?.FAILURE||!this.emailSending?.dsnOverride?.NOTIFY&&this.dsn?.NOTIFY?.FAILURE)&&e.push("FAILURE"),(this.emailSending?.dsnOverride?.NOTIFY&&this.emailSending?.dsnOverride?.NOTIFY?.DELAY||!this.emailSending?.dsnOverride?.NOTIFY&&this.dsn?.NOTIFY?.DELAY)&&e.push("DELAY"),e.length>0?` NOTIFY=${e.join(",")}`:" NOTIFY=NEVER"}retBuilder(){let e=[];return(this.emailSending?.dsnOverride?.RET&&this.emailSending?.dsnOverride?.RET?.HEADERS||!this.emailSending?.dsnOverride?.RET&&this.dsn?.RET?.HEADERS)&&e.push("HDRS"),(this.emailSending?.dsnOverride?.RET&&this.emailSending?.dsnOverride?.RET?.FULL||!this.emailSending?.dsnOverride?.RET&&this.dsn?.RET?.FULL)&&e.push("FULL"),e.length>0?`RET=${e.join(",")}`:""}};function j(r){return async function(t){let i=[];for(let s of t.messages){let{mailerOptions:o,emailOptions:h}=s.body,l={success:!1,emailOptions:h};try{await R.send(o,h),l.success=!0,s.ack(),await r?.onSuccess?.(l)}catch(d){l.error=d instanceof Error?d.message:String(d),s.retry(),await r?.onError?.(l)}i.push(l)}return i}}async function Y(r,e){await r.send(e)}async function Q(r,e){await r.sendBatch(e.map(t=>({body:t})))}0&&(module.exports={createQueueHandler,enqueueEmail,enqueueEmails});
package/dist/queue.mjs ADDED
@@ -0,0 +1 @@
1
+ import{m as n}from"./chunk-TXGT6IDZ.mjs";function E(e){return async function(o){let i=[];for(let u of o.messages){let{mailerOptions:c,emailOptions:t}=u.body,s={success:!1,emailOptions:t};try{await n.send(c,t),s.success=!0,u.ack(),await e?.onSuccess?.(s)}catch(a){s.error=a instanceof Error?a.message:String(a),u.retry(),await e?.onError?.(s)}i.push(s)}return i}}async function d(e,r){await e.send(r)}async function g(e,r){await e.sendBatch(r.map(o=>({body:o})))}export{E as createQueueHandler,d as enqueueEmail,g as enqueueEmails};
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@workermailer/smtp",
3
+ "version": "0.1.0",
4
+ "packageManager": "bun@1.3.11",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./queue": {
15
+ "types": "./dist/queue.d.ts",
16
+ "import": "./dist/queue.mjs",
17
+ "require": "./dist/queue.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "cloudflare",
25
+ "workers",
26
+ "cloudflare-workers",
27
+ "email",
28
+ "smtp"
29
+ ],
30
+ "author": "André Ribas (@RibasSu)",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/RibasSu/worker-mailer.git"
34
+ },
35
+ "license": "MIT",
36
+ "homepage": "https://workermailer.com/",
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org/"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "test": "vitest",
44
+ "format": "prettier '**/*.{json,ts,js,cjs,mjs,md}' --write --ignore-path .gitignore"
45
+ },
46
+ "devDependencies": {
47
+ "@changesets/cli": "^2.30.0",
48
+ "@cloudflare/vitest-pool-workers": "^0.12.21",
49
+ "@cloudflare/workers-types": "^4.20260317.1",
50
+ "@types/libqp": "^1.1.3",
51
+ "@types/node": "^25.5.0",
52
+ "letterparser": "^0.1.8",
53
+ "libqp": "^2.1.1",
54
+ "prettier": "^3.8.1",
55
+ "tsup": "^8.5.1",
56
+ "typescript": "^5.9.3",
57
+ "vitest": "^3.2.4",
58
+ "wrangler": "^4.78.0"
59
+ }
60
+ }