@schemavaults/send-email 0.4.0 → 0.5.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/README.md CHANGED
@@ -81,6 +81,23 @@ bunx schemavaults-send-email --transport smtp-primary send \
81
81
 
82
82
  Transport names are defined by whoever configures the mail-server; this package only validates that the value looks like an identifier. An unknown transport name is rejected by the mail-server, not by the client.
83
83
 
84
+ ### Set the sender
85
+
86
+ `from` is optional; when omitted, the mail-server sends from its configured default sender. Pass a bare address, or a display name followed by the address in angle brackets. Wrap a display name in double quotes when it contains any of `( ) [ ] : ; @ ,`:
87
+
88
+ ```ts
89
+ await sendEmail({
90
+ body: {
91
+ to: "user@example.com",
92
+ from: '"Example, Inc." <noreply@example.com>', // or "Example <noreply@example.com>", or "noreply@example.com"
93
+ subject: "Hello",
94
+ message: { text: "Hello.", html: "<p>Hello.</p>" },
95
+ },
96
+ });
97
+ ```
98
+
99
+ The address's domain must be one the mail-server's transport is set up to send from. On the CLI, pass the same value to `--from`.
100
+
84
101
  ### Attach files
85
102
 
86
103
  Request bodies are JSON, so each attachment's bytes travel as a base64 string under `body.attachments`. You rarely need to encode anything yourself: the `attachments` option on `sendEmail()` (and `sendEmailToMailingList()`) accepts raw bytes, plain text, or already-encoded attachments and base64-encodes them for you before appending them to `body.attachments`.
@@ -121,9 +138,9 @@ const attachment = createEmailAttachment({
121
138
  // => { filename: "logo.png", content: "iVBORw0KGgo...", contentType: "image/png", contentId: "logo" }
122
139
  ```
123
140
 
124
- Setting `contentId` marks the attachment as inline so the HTML body can embed it via a `cid:` URL; pass the bare identifier without angle brackets. `contentType` is optional -- when omitted, the mail-server's transport derives it from the filename's extension.
141
+ Setting `contentId` marks the attachment as inline so the HTML body can embed it via a `cid:` URL; pass the bare identifier without angle brackets, in printable ASCII. `contentType` is optional -- when omitted, the mail-server's transport derives it from the filename's extension. Non-ASCII names belong in `filename`, not in a `contentType` parameter.
125
142
 
126
- Limits enforced client-side (and exported as `MAX_ATTACHMENTS_PER_EMAIL` / `MAX_TOTAL_ATTACHMENT_BYTES`): at most 20 attachments per email, totalling at most 25 MiB once decoded. Filenames may not contain path separators or control characters. The mail-server, its hosting platform, and the receiving mail systems may enforce lower limits of their own.
143
+ Limits enforced client-side (and exported as `MAX_ATTACHMENTS_PER_EMAIL` / `MAX_TOTAL_ATTACHMENT_BYTES`): at most 20 attachments per email, totalling at most 25 MiB once decoded. Filenames may not contain path separators, control characters, or bidirectional formatting characters (which can disguise `invoice\u202Efdp.exe` as `invoiceexe.pdf`). `contentType` and `contentId` must be printable ASCII, and `subject` must not contain line breaks or other control characters, so no value can break out of its MIME header. The mail-server, its hosting platform, and the receiving mail systems may enforce lower limits of their own.
127
144
 
128
145
  From the CLI, `--attach <path>` is repeatable on both `send` and `send-to-mailing-list`, and may be combined with `--body-file` (the files are appended to any `attachments` already in the JSON):
129
146
 
@@ -272,6 +289,10 @@ Zod schema for validating template IDs: lowercase alphanumeric with hyphens/unde
272
289
 
273
290
  Zod schema for validating transport names: lowercase alphanumeric with hyphens/underscores, 1-64 characters, must start with a lowercase letter and end with a lowercase alphanumeric character. Whether a well-formed name corresponds to a transport the mail-server actually has configured is decided server-side.
274
291
 
292
+ ### `emailSenderSchema`
293
+
294
+ Zod schema for the `from` field: a bare address (`noreply@example.com`) or a display name followed by the address in angle brackets (`Example <noreply@example.com>`). Display names may be Unicode; one containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes (`"Example, Inc." <noreply@example.com>`). Control characters, bidi formatting characters, and angle brackets, double quotes or backslashes inside the display name are rejected.
295
+
275
296
  ### `emailAttachmentSchema` / `emailAttachmentsSchema`
276
297
 
277
298
  Zod schemas for a single attachment and for the `attachments` array respectively. The array schema enforces the count (`MAX_ATTACHMENTS_PER_EMAIL`, 20) and total decoded size (`MAX_TOTAL_ATTACHMENT_BYTES`, 25 MiB) limits; both constants are exported.
@@ -286,17 +307,17 @@ type Message =
286
307
  | { text: string; html: string }; // both required
287
308
 
288
309
  type EmailAttachment = {
289
- filename: string; // 1-255 chars; no path separators or control characters
310
+ filename: string; // 1-255 chars; no path separators, control or bidi formatting characters
290
311
  content: string; // base64-encoded bytes (standard alphabet, padded)
291
- contentType?: string; // MIME type; derived from the filename when omitted
292
- contentId?: string; // marks the attachment inline; reference as cid:<contentId>
312
+ contentType?: string; // MIME type, printable ASCII; derived from the filename when omitted
313
+ contentId?: string; // printable ASCII; marks the attachment inline; reference as cid:<contentId>
293
314
  };
294
315
 
295
316
  type SendEmailRequestBody = {
296
317
  to: string | string[]; // email address(es) or mailing list UUID
297
- subject: string;
318
+ subject: string; // no line breaks or control characters (tabs allowed)
298
319
  message: Message;
299
- from?: string; // defaults to mail-server's configured sender
320
+ from?: string; // address or "Display Name <address>"; defaults to mail-server's configured sender
300
321
  replyTo?: string;
301
322
  cc?: string | string[];
302
323
  bcc?: string | string[];
package/dist/cli.js CHANGED
@@ -18008,6 +18008,35 @@ var transportIdSchema = external_exports.string().min(1, "Transport ID must be n
18008
18008
  "Transport ID must start with a lowercase letter and end with a lowercase alphanumeric character, and may only contain lowercase alphanumeric characters, hyphens and underscores."
18009
18009
  );
18010
18010
 
18011
+ // src/validators/unsafe-characters.ts
18012
+ function hasControlCharacters(value) {
18013
+ for (let i = 0; i < value.length; i++) {
18014
+ const code = value.charCodeAt(i);
18015
+ if (code < 32 || code >= 127 && code <= 159) return true;
18016
+ }
18017
+ return false;
18018
+ }
18019
+ var BIDI_FORMATTING = /* @__PURE__ */ new Set([
18020
+ 1564,
18021
+ 8206,
18022
+ 8207,
18023
+ 8234,
18024
+ 8235,
18025
+ 8236,
18026
+ 8237,
18027
+ 8238,
18028
+ 8294,
18029
+ 8295,
18030
+ 8296,
18031
+ 8297
18032
+ ]);
18033
+ function hasBidiFormatting(value) {
18034
+ for (let i = 0; i < value.length; i++) {
18035
+ if (BIDI_FORMATTING.has(value.charCodeAt(i))) return true;
18036
+ }
18037
+ return false;
18038
+ }
18039
+
18011
18040
  // src/validators/email-attachment-schema.ts
18012
18041
  var MAX_ATTACHMENTS_PER_EMAIL = 20;
18013
18042
  var MAX_TOTAL_ATTACHMENT_BYTES = 25 * 1024 * 1024;
@@ -18018,31 +18047,28 @@ function base64DecodedByteLength(base643) {
18018
18047
  else if (base643.endsWith("=")) padding = 1;
18019
18048
  return Math.floor(base643.length * 3 / 4) - padding;
18020
18049
  }
18021
- function hasControlCharacters(value) {
18022
- for (let i = 0; i < value.length; i++) {
18023
- const code = value.charCodeAt(i);
18024
- if (code < 32 || code === 127) return true;
18025
- }
18026
- return false;
18027
- }
18028
18050
  var attachmentFilenameSchema = external_exports.string().min(1, "Attachment filename must be non-empty!").max(255, "Attachment filename must be at most 255 characters!").refine((name) => name !== "." && name !== "..", {
18029
18051
  message: "Attachment filename must not be '.' or '..'!"
18030
18052
  }).refine((name) => !name.includes("/") && !name.includes("\\"), {
18031
18053
  message: "Attachment filename must not contain path separators!"
18032
18054
  }).refine((name) => !hasControlCharacters(name), {
18033
18055
  message: "Attachment filename must not contain control characters!"
18056
+ }).refine((name) => !hasBidiFormatting(name), {
18057
+ message: "Attachment filename must not contain bidirectional formatting characters!"
18034
18058
  });
18035
18059
  var attachmentContentSchema = external_exports.base64("Attachment content must be base64-encoded!").min(1, "Attachment content must not be empty!");
18036
18060
  var MIME_TOKEN = "[A-Za-z0-9!#$&^_.+-]+";
18061
+ var MIME_PARAM_VALUE = '(?:"[\\x20\\x21\\x23-\\x7E]*"|[\\x21\\x23-\\x3A\\x3C-\\x7E]+)';
18037
18062
  var attachmentContentTypeSchema = external_exports.string().min(1, "Attachment content type must be non-empty!").max(255, "Attachment content type must be at most 255 characters!").regex(
18063
+ // `[ \t]*`, not `\s*`: `\s` matches CR/LF.
18038
18064
  new RegExp(
18039
- `^${MIME_TOKEN}\\/${MIME_TOKEN}(?:\\s*;\\s*${MIME_TOKEN}=(?:"[^"]*"|[^\\s;"]+))*$`
18065
+ `^${MIME_TOKEN}\\/${MIME_TOKEN}(?:[ \\t]*;[ \\t]*${MIME_TOKEN}=${MIME_PARAM_VALUE})*$`
18040
18066
  ),
18041
18067
  "Attachment content type must be a MIME type such as 'application/pdf'!"
18042
18068
  );
18043
18069
  var attachmentContentIdSchema = external_exports.string().min(1, "Attachment content ID must be non-empty!").max(255, "Attachment content ID must be at most 255 characters!").regex(
18044
- /^[^\s<>]+$/,
18045
- "Attachment content ID must not contain whitespace or angle brackets!"
18070
+ /^[\x21-\x3B\x3D\x3F-\x7E]+$/,
18071
+ "Attachment content ID must be printable ASCII without spaces or angle brackets!"
18046
18072
  );
18047
18073
  var emailAttachmentSchema = external_exports.object({
18048
18074
  filename: attachmentFilenameSchema,
@@ -18069,6 +18095,46 @@ var emailAttachmentsSchema = external_exports.array(emailAttachmentSchema).min(1
18069
18095
  }
18070
18096
  });
18071
18097
 
18098
+ // src/validators/email-sender-schema.ts
18099
+ var emailAddressSchema = external_exports.string().email();
18100
+ var DISPLAY_NAME_SPECIALS = /[()[\]:;@,]/;
18101
+ function describeEmailSenderProblem(value) {
18102
+ if (hasControlCharacters(value)) {
18103
+ return "Sender must not contain line breaks or control characters!";
18104
+ }
18105
+ if (hasBidiFormatting(value)) {
18106
+ return "Sender must not contain bidirectional formatting characters!";
18107
+ }
18108
+ if (emailAddressSchema.safeParse(value).success) return null;
18109
+ const open = value.lastIndexOf("<");
18110
+ if (open < 0 || !value.endsWith(">") || value.trim() !== value) {
18111
+ return "Sender must be an email address (noreply@example.com) or a display name followed by an address in angle brackets (Example <noreply@example.com>)!";
18112
+ }
18113
+ const address = value.slice(open + 1, -1);
18114
+ const name = value.slice(0, open).trimEnd();
18115
+ if (!emailAddressSchema.safeParse(address).success) {
18116
+ return "Sender address in angle brackets must be a valid email address!";
18117
+ }
18118
+ const quoted = name.length >= 2 && name.startsWith('"') && name.endsWith('"');
18119
+ const text = quoted ? name.slice(1, -1) : name;
18120
+ if (text.trim().length === 0) {
18121
+ return "Sender display name must not be empty!";
18122
+ }
18123
+ if (/[<>"\\]/.test(text)) {
18124
+ return "Sender display name must not contain angle brackets, double quotes or backslashes!";
18125
+ }
18126
+ if (!quoted && DISPLAY_NAME_SPECIALS.test(text)) {
18127
+ return 'Sender display names containing ( ) [ ] : ; @ or , must be wrapped in double quotes (e.g. "Example, Inc." <noreply@example.com>)!';
18128
+ }
18129
+ return null;
18130
+ }
18131
+ var emailSenderSchema = external_exports.string().superRefine((value, ctx) => {
18132
+ const problem = describeEmailSenderProblem(value);
18133
+ if (problem !== null) {
18134
+ ctx.addIssue({ code: "custom", message: problem });
18135
+ }
18136
+ });
18137
+
18072
18138
  // src/send-email-request-body-schema.ts
18073
18139
  var sendEmailTemplateOptions = external_exports.object({
18074
18140
  template_id: emailTemplateIdSchema,
@@ -18084,6 +18150,13 @@ var sendRawEmailOptions = external_exports.object({
18084
18150
  html: true
18085
18151
  }).strict();
18086
18152
  var MAX_RECIPIENTS = 50;
18153
+ function hasHeaderUnsafeCharacters(value) {
18154
+ for (let i = 0; i < value.length; i++) {
18155
+ const code = value.charCodeAt(i);
18156
+ if (code < 32 && code !== 9 || code === 127) return true;
18157
+ }
18158
+ return false;
18159
+ }
18087
18160
  function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
18088
18161
  if (allow_mailing_list_ids_as_recipients) {
18089
18162
  return external_exports.union([
@@ -18106,8 +18179,15 @@ function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
18106
18179
  function createSendEmailRequestBodySchema(allow_mailing_list_ids_as_recipients = false) {
18107
18180
  return external_exports.object({
18108
18181
  to: createRecipientSchema(allow_mailing_list_ids_as_recipients),
18109
- from: external_exports.string().email().optional(),
18110
- subject: external_exports.string().nonempty(),
18182
+ /**
18183
+ * Who the email is from: a bare address, or a display name followed by
18184
+ * the address in angle brackets ("Example <noreply@example.com>").
18185
+ * When omitted, the mail-server uses its configured default sender.
18186
+ */
18187
+ from: emailSenderSchema.optional(),
18188
+ subject: external_exports.string().nonempty().refine((subject) => !hasHeaderUnsafeCharacters(subject), {
18189
+ message: "Subject must not contain line breaks or control characters!"
18190
+ }),
18111
18191
  message: external_exports.union([sendEmailTemplateOptions, sendRawEmailOptions]),
18112
18192
  replyTo: external_exports.string().email().optional(),
18113
18193
  cc: external_exports.union([
@@ -18447,7 +18527,10 @@ async function withErrorHandling(fn) {
18447
18527
  }
18448
18528
  }
18449
18529
  function attachBodyOptions(cmd) {
18450
- return cmd.option("--from <email>", "Sender email address").option("--subject <subject>", "Email subject").option("--reply-to <email>", "Reply-To email address").option(
18530
+ return cmd.option(
18531
+ "--from <sender>",
18532
+ 'Sender email address, optionally with a display name ("Example <noreply@example.com>")'
18533
+ ).option("--subject <subject>", "Email subject").option("--reply-to <email>", "Reply-To email address").option(
18451
18534
  "--template-id <id>",
18452
18535
  "Email template ID (mutually exclusive with --text/--html)"
18453
18536
  ).option(
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,SAAS;AAET,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,SAAS,MAAM,cAAc,CAAC;AACrC,OAAO,sBAAsB,MAAM,8BAA8B,CAAC;AAClE,OAAO,kBAAkB,MAAM,wBAAwB,CAAC;AACxD,OAAO,6BAA6B,MAAM,qCAAqC,CAAC;AA4ChF,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAuB;IACjD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,6CAA6C,GAAG,EAAE,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,IAAiB;IACrC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,OAAO,KAAK,KAAK,SAAS;YACxB,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE;YAC7D,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,IAAI,GACR,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACzE,MAAM,IAAI,GACR,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACzE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,aAAa,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,KAA2B;IAE3B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5C,OAAO,MAAM,OAAO,CAAC,GAAG,CACtB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,CACzD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,EAAuB;IACtD,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,CAAC;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAY;IACrC,OAAO,GAAG;SACP,MAAM,CACL,iBAAiB,EACjB,wFAAwF,CACzF;SACA,MAAM,CAAC,qBAAqB,EAAE,eAAe,CAAC;SAC9C,MAAM,CAAC,oBAAoB,EAAE,wBAAwB,CAAC;SACtD,MAAM,CACL,oBAAoB,EACpB,2DAA2D,CAC5D;SACA,MAAM,CACL,yBAAyB,EACzB,kDAAkD,CACnD;SACA,MAAM,CAAC,eAAe,EAAE,mCAAmC,CAAC;SAC5D,MAAM,CAAC,eAAe,EAAE,6BAA6B,CAAC;SACtD,MAAM,CACL,oBAAoB,EACpB,+CAA+C,CAChD;SACA,MAAM,CAAC,oBAAoB,EAAE,yCAAyC,CAAC;SACvE,MAAM,CACL,oBAAoB,EACpB,qFAAqF,CACtF;SACA,MAAM,CACL,oBAAoB,EACpB,sHAAsH,CACvH,CAAC;AACN,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,yBAAyB,CAAC;KAC/B,WAAW,CAAC,yDAAyD,CAAC;KACtE,MAAM,CACL,iBAAiB,EACjB,8DAA8D,CAC/D;KACA,SAAS,CACR,IAAI,MAAM,CACR,qBAAqB,EACrB,iCAAiC,CAClC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CACpD;KACA,MAAM,CACL,WAAW,EACX,gEAAgE,CACjE;KACA,MAAM,CACL,oBAAoB,EACpB,wGAAwG,CACzG,CAAC;AAEJ,iBAAiB,CACf,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,iBAAiB,EAAE,sCAAsC,CAAC;KACjE,MAAM,CAAC,iBAAiB,EAAE,2BAA2B,CAAC;KACtD,MAAM,CAAC,kBAAkB,EAAE,4BAA4B,CAAC,CAC5D,CAAC,MAAM,CAAC,KAAK,EAAE,IAAc,EAAE,GAAY,EAAE,EAAE;IAC9C,MAAM,iBAAiB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,EAAc,CAAC;QAEjD,IAAI,IAA0B,CAAC;QAC/B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;YACD,IAAI,GAAG;gBACL,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;gBAC/C,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC;gBAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;oBAC/B,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE;oBACrD,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;oBACjC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;oBACzD,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEvD,MAAM,SAAS,CAAC;YACd,IAAI;YACJ,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7D,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,MAAM;YACX,CAAC,CAAC,6CAA6C;YAC/C,CAAC,CAAC,aAAa,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iBAAiB,CACf,OAAO;KACJ,OAAO,CAAC,sBAAsB,CAAC;KAC/B,WAAW,CAAC,8CAA8C,CAAC;KAC3D,MAAM,CACL,0BAA0B,EAC1B,sEAAsE,CACvE,CACJ,CAAC,MAAM,CAAC,KAAK,EAAE,IAAqB,EAAE,GAAY,EAAE,EAAE;IACrD,MAAM,iBAAiB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,EAAc,CAAC;QAEjD,IAAI,IAAqD,CAAC;QAC1D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,GAAG;gBACL,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1D,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChE,GAAG,CAAC,QAAQ,CAAC,WAAW;oBACtB,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE;oBACvC,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;YACD,IAAI,GAAG;gBACL,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC;gBAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnD,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEvD,MAAM,sBAAsB,CAAC;YAC3B,IAAI;YACJ,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7D,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,MAAM;YACX,CAAC,CAAC,0DAA0D;YAC5D,CAAC,CAAC,6BAA6B,CAClC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,gCAAgC,CAAC;KAC7C,SAAS,CACR,IAAI,MAAM,CAAC,gBAAgB,EAAE,eAAe,CAAC;KAC1C,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC1B,OAAO,CAAC,MAAM,CAAC,CACnB;KACA,MAAM,CAAC,KAAK,EAAE,IAAuB,EAAE,GAAY,EAAE,EAAE;IACtD,MAAM,iBAAiB,CAAC,KAAK,IAAI,EAAE;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,EAAc,CAAC;QACjD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC5B,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { sendEmailRequestBodySchema, createSendEmailRequestBodySchema, } from ".
2
2
  export type { SendEmailRequestBody } from "./send-email-request-body-schema.js";
3
3
  export { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
4
4
  export { transportIdSchema } from "./validators/transport-id-schema.js";
5
+ export { emailSenderSchema } from "./validators/email-sender-schema.js";
5
6
  export { emailAttachmentSchema, emailAttachmentsSchema, MAX_ATTACHMENTS_PER_EMAIL, MAX_TOTAL_ATTACHMENT_BYTES, } from "./validators/email-attachment-schema.js";
6
7
  export type { EmailAttachment } from "./validators/email-attachment-schema.js";
7
8
  export { createEmailAttachment } from "./create-email-attachment.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { sendEmailRequestBodySchema, createSendEmailRequestBodySchema, } from "./send-email-request-body-schema.js";
2
2
  export { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
3
3
  export { transportIdSchema } from "./validators/transport-id-schema.js";
4
+ export { emailSenderSchema } from "./validators/email-sender-schema.js";
4
5
  export { emailAttachmentSchema, emailAttachmentsSchema, MAX_ATTACHMENTS_PER_EMAIL, MAX_TOTAL_ATTACHMENT_BYTES, } from "./validators/email-attachment-schema.js";
5
6
  export { createEmailAttachment } from "./create-email-attachment.js";
6
7
  export { sendEmail, sendEmail as default, } from "./send-email.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EACL,SAAS,EACT,SAAS,IAAI,OAAO,GACrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EACL,SAAS,EACT,SAAS,IAAI,OAAO,GACrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
3
3
  import { transportIdSchema } from "./validators/transport-id-schema.js";
4
4
  import { emailAttachmentsSchema } from "./validators/email-attachment-schema.js";
5
+ import { emailSenderSchema } from "./validators/email-sender-schema.js";
5
6
  const sendEmailTemplateOptions = z
6
7
  .object({
7
8
  template_id: emailTemplateIdSchema,
@@ -22,6 +23,16 @@ const sendRawEmailOptions = z
22
23
  })
23
24
  .strict();
24
25
  const MAX_RECIPIENTS = 50;
26
+ // C0 controls except HTAB, plus DEL: a line break in a header value can
27
+ // start a new header (e.g. `Bcc:`).
28
+ function hasHeaderUnsafeCharacters(value) {
29
+ for (let i = 0; i < value.length; i++) {
30
+ const code = value.charCodeAt(i);
31
+ if ((code < 0x20 && code !== 0x09) || code === 0x7f)
32
+ return true;
33
+ }
34
+ return false;
35
+ }
25
36
  export function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
26
37
  if (allow_mailing_list_ids_as_recipients) {
27
38
  return z.union([
@@ -46,8 +57,18 @@ export function createSendEmailRequestBodySchema(allow_mailing_list_ids_as_recip
46
57
  return z
47
58
  .object({
48
59
  to: createRecipientSchema(allow_mailing_list_ids_as_recipients),
49
- from: z.string().email().optional(),
50
- subject: z.string().nonempty(),
60
+ /**
61
+ * Who the email is from: a bare address, or a display name followed by
62
+ * the address in angle brackets ("Example <noreply@example.com>").
63
+ * When omitted, the mail-server uses its configured default sender.
64
+ */
65
+ from: emailSenderSchema.optional(),
66
+ subject: z
67
+ .string()
68
+ .nonempty()
69
+ .refine((subject) => !hasHeaderUnsafeCharacters(subject), {
70
+ message: "Subject must not contain line breaks or control characters!",
71
+ }),
51
72
  message: z.union([sendEmailTemplateOptions, sendRawEmailOptions]),
52
73
  replyTo: z.string().email().optional(),
53
74
  cc: z
@@ -1 +1 @@
1
- {"version":3,"file":"send-email-request-body-schema.js","sourceRoot":"","sources":["../src/send-email-request-body-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAE9E,MAAM,wBAAwB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,WAAW,EAAE,qBAAqB;IAClC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;CAC5B,CAAC;KACD,QAAQ,CAAC;IACR,WAAW,EAAE,IAAI;CAClB,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC;KACD,QAAQ,CAAC;IACR,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;CACX,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,cAAc,GAAW,EAAE,CAAC;AAElC,MAAM,UAAU,qBAAqB,CACnC,uCAAgD,KAAK;IAErD,IAAI,oCAAoC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC,KAAK,CAAC;YACb,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,mBAAmB;YACvC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,kBAAkB;YACzE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,+BAA+B;SACnD,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,CAAC,KAAK,CAAC;YACb,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,mBAAmB;YACvC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,kBAAkB;SAC1E,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAC9C,uCAAgD,KAAK;IAErD,OAAO,CAAC;SACL,MAAM,CAAC;QACN,EAAE,EAAE,qBAAqB,CAAC,oCAAoC,CAAC;QAC/D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;QACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC;QACjE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;QACtC,EAAE,EAAE,CAAC;aACF,KAAK,CAAC;YACL,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;YAClB,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;SACtD,CAAC;aACD,QAAQ,EAAE;QACb,GAAG,EAAE,CAAC;aACH,KAAK,CAAC;YACL,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;YAClB,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;SACtD,CAAC;aACD,QAAQ,EAAE;QACb,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC9B;;;;;WAKG;QACH,SAAS,EAAE,iBAAiB,CAAC,QAAQ,EAAE;QACvC;;;;;;WAMG;QACH,WAAW,EAAE,sBAAsB,CAAC,QAAQ,EAAE;KAC/C,CAAC;SACD,QAAQ,CAAC;QACR,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;KACd,CAAC;SACD,MAAM,EAAE,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,gCAAgC,EAAE,CAAC;AAM7E,eAAe,gCAAgC,CAAC"}
1
+ {"version":3,"file":"send-email-request-body-schema.js","sourceRoot":"","sources":["../src/send-email-request-body-schema.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,8 @@ export declare const MAX_TOTAL_ATTACHMENT_BYTES: number;
18
18
  export declare function base64DecodedByteLength(base64: string): number;
19
19
  /**
20
20
  * Name the recipient's mail client shows for the attached file. Unicode is
21
- * allowed; path separators and control characters are not.
21
+ * allowed; path separators, control characters and bidirectional formatting
22
+ * characters are not.
22
23
  */
23
24
  export declare const attachmentFilenameSchema: z.ZodString;
24
25
  /**
@@ -29,14 +30,16 @@ export declare const attachmentFilenameSchema: z.ZodString;
29
30
  export declare const attachmentContentSchema: z.ZodBase64;
30
31
  /**
31
32
  * MIME type of the attachment, e.g. "application/pdf" or
32
- * "text/csv; charset=utf-8". When omitted, the mail-server's transport
33
- * derives it from the filename's extension.
33
+ * "text/csv; charset=utf-8". Printable ASCII only. When omitted, the
34
+ * mail-server's transport derives it from the filename's extension.
34
35
  */
35
36
  export declare const attachmentContentTypeSchema: z.ZodString;
36
37
  /**
37
38
  * Content-ID for inline attachments. Setting it marks the attachment as
38
39
  * inline so the HTML body can reference it as `<img src="cid:<contentId>">`.
39
- * Pass the bare identifier -- without the angle brackets.
40
+ * Pass the bare identifier -- without the angle brackets. Content-ID is an
41
+ * ASCII header; anything else is emitted as an encoded-word that no longer
42
+ * matches the HTML's `cid:` reference.
40
43
  */
41
44
  export declare const attachmentContentIdSchema: z.ZodString;
42
45
  /**
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { hasBidiFormatting, hasControlCharacters, } from "../validators/unsafe-characters.js";
2
3
  /**
3
4
  * Maximum number of attachments accepted on a single email.
4
5
  */
@@ -25,17 +26,10 @@ export function base64DecodedByteLength(base64) {
25
26
  padding = 1;
26
27
  return Math.floor((base64.length * 3) / 4) - padding;
27
28
  }
28
- function hasControlCharacters(value) {
29
- for (let i = 0; i < value.length; i++) {
30
- const code = value.charCodeAt(i);
31
- if (code < 0x20 || code === 0x7f)
32
- return true;
33
- }
34
- return false;
35
- }
36
29
  /**
37
30
  * Name the recipient's mail client shows for the attached file. Unicode is
38
- * allowed; path separators and control characters are not.
31
+ * allowed; path separators, control characters and bidirectional formatting
32
+ * characters are not.
39
33
  */
40
34
  export const attachmentFilenameSchema = z
41
35
  .string()
@@ -49,6 +43,9 @@ export const attachmentFilenameSchema = z
49
43
  })
50
44
  .refine((name) => !hasControlCharacters(name), {
51
45
  message: "Attachment filename must not contain control characters!",
46
+ })
47
+ .refine((name) => !hasBidiFormatting(name), {
48
+ message: "Attachment filename must not contain bidirectional formatting characters!",
52
49
  });
53
50
  /**
54
51
  * The attached file's bytes, base64-encoded (standard alphabet, padded, no
@@ -59,26 +56,34 @@ export const attachmentContentSchema = z
59
56
  .base64("Attachment content must be base64-encoded!")
60
57
  .min(1, "Attachment content must not be empty!");
61
58
  const MIME_TOKEN = "[A-Za-z0-9!#$&^_.+-]+";
59
+ // Printable ASCII only, so no value can carry CR/LF or other controls out of
60
+ // its header. Quoted: anything printable but `"`. Unquoted: printable minus
61
+ // space, `"` and `;`.
62
+ const MIME_PARAM_VALUE = '(?:"[\\x20\\x21\\x23-\\x7E]*"|[\\x21\\x23-\\x3A\\x3C-\\x7E]+)';
62
63
  /**
63
64
  * MIME type of the attachment, e.g. "application/pdf" or
64
- * "text/csv; charset=utf-8". When omitted, the mail-server's transport
65
- * derives it from the filename's extension.
65
+ * "text/csv; charset=utf-8". Printable ASCII only. When omitted, the
66
+ * mail-server's transport derives it from the filename's extension.
66
67
  */
67
68
  export const attachmentContentTypeSchema = z
68
69
  .string()
69
70
  .min(1, "Attachment content type must be non-empty!")
70
71
  .max(255, "Attachment content type must be at most 255 characters!")
71
- .regex(new RegExp(`^${MIME_TOKEN}\\/${MIME_TOKEN}(?:\\s*;\\s*${MIME_TOKEN}=(?:"[^"]*"|[^\\s;"]+))*$`), "Attachment content type must be a MIME type such as 'application/pdf'!");
72
+ .regex(
73
+ // `[ \t]*`, not `\s*`: `\s` matches CR/LF.
74
+ new RegExp(`^${MIME_TOKEN}\\/${MIME_TOKEN}(?:[ \\t]*;[ \\t]*${MIME_TOKEN}=${MIME_PARAM_VALUE})*$`), "Attachment content type must be a MIME type such as 'application/pdf'!");
72
75
  /**
73
76
  * Content-ID for inline attachments. Setting it marks the attachment as
74
77
  * inline so the HTML body can reference it as `<img src="cid:<contentId>">`.
75
- * Pass the bare identifier -- without the angle brackets.
78
+ * Pass the bare identifier -- without the angle brackets. Content-ID is an
79
+ * ASCII header; anything else is emitted as an encoded-word that no longer
80
+ * matches the HTML's `cid:` reference.
76
81
  */
77
82
  export const attachmentContentIdSchema = z
78
83
  .string()
79
84
  .min(1, "Attachment content ID must be non-empty!")
80
85
  .max(255, "Attachment content ID must be at most 255 characters!")
81
- .regex(/^[^\s<>]+$/, "Attachment content ID must not contain whitespace or angle brackets!");
86
+ .regex(/^[\x21-\x3B\x3D\x3F-\x7E]+$/, "Attachment content ID must be printable ASCII without spaces or angle brackets!");
82
87
  /**
83
88
  * A single file attached to an email, in the shape accepted by the
84
89
  * `@schemavaults/mail-server` `/api/send` route.
@@ -1 +1 @@
1
- {"version":3,"file":"email-attachment-schema.js","sourceRoot":"","sources":["../../src/validators/email-attachment-schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"email-attachment-schema.js","sourceRoot":"","sources":["../../src/validators/email-attachment-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Who an email is from: a bare address ("noreply@example.com"), or a display
4
+ * name followed by the address in angle brackets
5
+ * ("Example <noreply@example.com>"). Unicode display names are allowed; one
6
+ * containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes
7
+ * ('"Example, Inc." <noreply@example.com>'). Control characters, bidi
8
+ * formatting characters, and angle brackets, double quotes or backslashes
9
+ * within the display name are rejected.
10
+ */
11
+ export declare const emailSenderSchema: z.ZodString;
12
+ export default emailSenderSchema;
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ import { hasBidiFormatting, hasControlCharacters, } from "../validators/unsafe-characters.js";
3
+ const emailAddressSchema = z.string().email();
4
+ // RFC 5322 specials a display name may only carry inside double quotes.
5
+ // "." is a special too, but every mail client accepts it unquoted (as in
6
+ // "Example Inc. <noreply@example.com>"), so it is allowed.
7
+ const DISPLAY_NAME_SPECIALS = /[()[\]:;@,]/;
8
+ /**
9
+ * Why `value` is not an acceptable sender, or null when it is. Accepts a bare
10
+ * address, or a display name followed by the address in angle brackets.
11
+ */
12
+ function describeEmailSenderProblem(value) {
13
+ if (hasControlCharacters(value)) {
14
+ return "Sender must not contain line breaks or control characters!";
15
+ }
16
+ if (hasBidiFormatting(value)) {
17
+ return "Sender must not contain bidirectional formatting characters!";
18
+ }
19
+ if (emailAddressSchema.safeParse(value).success)
20
+ return null;
21
+ // Split on the last "<" rather than with a regex: one with optional spaces
22
+ // around the split backtracks quadratically on long input. Any other angle
23
+ // bracket is rejected below, so the bracketed address is the only one.
24
+ const open = value.lastIndexOf("<");
25
+ if (open < 0 || !value.endsWith(">") || value.trim() !== value) {
26
+ return "Sender must be an email address (noreply@example.com) or a display name followed by an address in angle brackets (Example <noreply@example.com>)!";
27
+ }
28
+ const address = value.slice(open + 1, -1);
29
+ const name = value.slice(0, open).trimEnd();
30
+ if (!emailAddressSchema.safeParse(address).success) {
31
+ return "Sender address in angle brackets must be a valid email address!";
32
+ }
33
+ const quoted = name.length >= 2 && name.startsWith('"') && name.endsWith('"');
34
+ const text = quoted ? name.slice(1, -1) : name;
35
+ if (text.trim().length === 0) {
36
+ return "Sender display name must not be empty!";
37
+ }
38
+ if (/[<>"\\]/.test(text)) {
39
+ return "Sender display name must not contain angle brackets, double quotes or backslashes!";
40
+ }
41
+ if (!quoted && DISPLAY_NAME_SPECIALS.test(text)) {
42
+ return 'Sender display names containing ( ) [ ] : ; @ or , must be wrapped in double quotes (e.g. "Example, Inc." <noreply@example.com>)!';
43
+ }
44
+ return null;
45
+ }
46
+ /**
47
+ * Who an email is from: a bare address ("noreply@example.com"), or a display
48
+ * name followed by the address in angle brackets
49
+ * ("Example <noreply@example.com>"). Unicode display names are allowed; one
50
+ * containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes
51
+ * ('"Example, Inc." <noreply@example.com>'). Control characters, bidi
52
+ * formatting characters, and angle brackets, double quotes or backslashes
53
+ * within the display name are rejected.
54
+ */
55
+ export const emailSenderSchema = z.string().superRefine((value, ctx) => {
56
+ const problem = describeEmailSenderProblem(value);
57
+ if (problem !== null) {
58
+ ctx.addIssue({ code: "custom", message: problem });
59
+ }
60
+ });
61
+ export default emailSenderSchema;
62
+ //# sourceMappingURL=email-sender-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-sender-schema.js","sourceRoot":"","sources":["../../src/validators/email-sender-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AAExC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;AAE9C,wEAAwE;AACxE,yEAAyE;AACzE,2DAA2D;AAC3D,MAAM,qBAAqB,GAAG,aAAa,CAAC;AAE5C;;;GAGG;AACH,SAAS,0BAA0B,CAAC,KAAa;IAC/C,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,4DAA4D,CAAC;IACtE,CAAC;IACD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,8DAA8D,CAAC;IACxE,CAAC;IACD,IAAI,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE7D,2EAA2E;IAC3E,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;QAC/D,OAAO,mJAAmJ,CAAC;IAC7J,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5C,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;QACnD,OAAO,iEAAiE,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,wCAAwC,CAAC;IAClD,CAAC;IACD,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,oFAAoF,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,mIAAmI,CAAC;IAC7I,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACrE,MAAM,OAAO,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function hasControlCharacters(value: string): boolean;
2
+ export declare function hasBidiFormatting(value: string): boolean;
@@ -0,0 +1,25 @@
1
+ // C0, DEL and C1 controls.
2
+ export function hasControlCharacters(value) {
3
+ for (let i = 0; i < value.length; i++) {
4
+ const code = value.charCodeAt(i);
5
+ if (code < 0x20 || (code >= 0x7f && code <= 0x9f))
6
+ return true;
7
+ }
8
+ return false;
9
+ }
10
+ // Bidirectional formatting characters (ALM, LRM, RLM, LRE through RLO, LRI
11
+ // through PDI) let a filename like "invoice<U+202E>fdp.exe" display as
12
+ // "invoiceexe.pdf". Listed as code points because the characters are
13
+ // invisible in source.
14
+ const BIDI_FORMATTING = new Set([
15
+ 0x061c, 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x2066,
16
+ 0x2067, 0x2068, 0x2069,
17
+ ]);
18
+ export function hasBidiFormatting(value) {
19
+ for (let i = 0; i < value.length; i++) {
20
+ if (BIDI_FORMATTING.has(value.charCodeAt(i)))
21
+ return true;
22
+ }
23
+ return false;
24
+ }
25
+ //# sourceMappingURL=unsafe-characters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsafe-characters.js","sourceRoot":"","sources":["../../src/validators/unsafe-characters.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,2EAA2E;AAC3E,uEAAuE;AACvE,qEAAqE;AACrE,uBAAuB;AACvB,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACtE,MAAM,EAAE,MAAM,EAAE,MAAM;CACvB,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@schemavaults/send-email",
3
3
  "description": "Schema defining the shape of the request body to send an email via @schemavaults/mail-server",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
7
7
  "repository": {