mailery 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CU_EApC6.cjs';
2
- export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CU_EApC6.cjs';
1
+ import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CfzvqNEp.cjs';
2
+ export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CfzvqNEp.cjs';
3
3
  import { ObjectId, Db, Filter } from 'mongodb';
4
4
  import { Request, Router } from 'express';
5
5
  import Handlebars from 'handlebars';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CU_EApC6.js';
2
- export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CU_EApC6.js';
1
+ import { R as RunnerContext, N as NormalizedEvent, C as ContactAdapter, a as Contact, A as AdapterFilter, M as MailProvider, S as SendArgs, b as SendResult, c as MailTesterFeedback, d as Mailer, T as TemplateDoc, e as SuppressionScope, D as DeliveryWindow, F as FlowStep, f as SegmentFilter, P as Predicate } from './null-CfzvqNEp.js';
2
+ export { g as AuditLogDoc, B as BroadcastDoc, h as BroadcastStatus, i as CircuitBreakerThresholds, j as Collections, k as ContactTagDoc, E as EventDoc, l as FlowDoc, m as FlowGoal, n as FlowRunDoc, o as FlowRunStatus, p as FlowVersionDoc, H as HealthDoc, q as HealthStatus, L as LeadDoc, r as MailerConfig, s as NullProvider, O as OutboxDoc, t as RESERVED_VAR_KEYS, u as RedisOptions, v as SegmentDefinition, w as SendDoc, x as SendStatus, y as SenderDomainConfig, z as SenderDomainRegistry, G as SenderDomainValidation, I as SubscriptionDoc, J as SubscriptionStatus, K as SuppressionDoc, Q as SuppressionReason, U as TemplateKind, V as TemplateVersionDoc, W as VarsAdapter, X as VarsResolveInfo, Y as WebhookEventDoc, Z as defineVars, _ as ensureIndexes, $ as getCollections, a0 as validateSenderDomain, a1 as varsJsonSchema } from './null-CfzvqNEp.js';
3
3
  import { ObjectId, Db, Filter } from 'mongodb';
4
4
  import { Request, Router } from 'express';
5
5
  import Handlebars from 'handlebars';
package/dist/index.js CHANGED
@@ -304,7 +304,10 @@ var init_sendgrid = __esm({
304
304
  replyTo: args.replyTo,
305
305
  subject: args.subject,
306
306
  text: args.text,
307
- html: args.html,
307
+ // Omit the key entirely rather than sending `html: undefined` — a
308
+ // text_only template must produce a single-part text/plain message, and
309
+ // an explicit undefined can still serialize into an empty HTML part.
310
+ ...args.html ? { html: args.html } : {},
308
311
  headers: args.headers,
309
312
  customArgs: args.messageMeta,
310
313
  trackingSettings: {
@@ -2143,7 +2146,8 @@ async function dispatchSend(sendId, ctx) {
2143
2146
  await markFailed(send._id, `render error: ${String(err?.message ?? err)}`, ctx);
2144
2147
  throw err;
2145
2148
  }
2146
- const tracking = applyTracking(rendered.html, {
2149
+ const textOnly = template.bodyFormat === "text_only";
2150
+ const tracking = textOnly ? { html: "", links: [] } : applyTracking(rendered.html, {
2147
2151
  sendId: String(send._id),
2148
2152
  publicUrl: ctx.config.publicUrl,
2149
2153
  trackOpens: template.trackOpens ?? ctx.config.trackOpens,
@@ -2155,7 +2159,9 @@ async function dispatchSend(sendId, ctx) {
2155
2159
  {
2156
2160
  $set: {
2157
2161
  links: tracking.links,
2158
- bodyHash: sha256(tracking.html),
2162
+ // Hash what actually goes out, so a text_only send's fingerprint
2163
+ // tracks the text body rather than an HTML part it never had.
2164
+ bodyHash: sha256(textOnly ? rendered.plainText : tracking.html),
2159
2165
  status: "sending",
2160
2166
  fromName: rendered.fromName,
2161
2167
  fromEmail: rendered.fromEmail,
@@ -2180,7 +2186,7 @@ async function dispatchSend(sendId, ctx) {
2180
2186
  fromEmail: rendered.fromEmail,
2181
2187
  replyTo: rendered.replyTo ?? void 0,
2182
2188
  subject: rendered.subject,
2183
- html: tracking.html,
2189
+ ...textOnly ? {} : { html: tracking.html },
2184
2190
  text: rendered.plainText,
2185
2191
  headers,
2186
2192
  messageMeta: { sendId: String(send._id) }
@@ -4811,6 +4817,9 @@ function isAllCaps(subject) {
4811
4817
  // src/server/api/admin.ts
4812
4818
  init_vars();
4813
4819
 
4820
+ // src/shared/enums.ts
4821
+ var TEMPLATE_BODY_FORMATS = ["multipart", "text_only"];
4822
+
4814
4823
  // src/server/api/setup-status.ts
4815
4824
  async function runSetupChecks(mailer) {
4816
4825
  const checks = [];
@@ -6470,6 +6479,7 @@ function apiRouter(mailer, opts = {}) {
6470
6479
  lastModifiedAt: now
6471
6480
  },
6472
6481
  tags: [],
6482
+ bodyFormat: "multipart",
6473
6483
  trackOpens: kind === "marketing",
6474
6484
  trackClicks: kind === "marketing",
6475
6485
  stats: { sent: 0, delivered: 0, opened: 0, clicked: 0, bounced: 0, complained: 0, unsubscribed: 0, lastSentAt: null },
@@ -6495,7 +6505,7 @@ function apiRouter(mailer, opts = {}) {
6495
6505
  asyncHandler(async (req, res) => {
6496
6506
  const tpl = await c.templates.findOne({ slug: req.params.slug });
6497
6507
  if (!tpl) return res.status(404).json({ error: "not_found" });
6498
- const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, trackOpens, trackClicks } = req.body ?? {};
6508
+ const { subject, preheader, mjml, editorJson, notes, name, fromName, fromEmail, replyTo, kind, bodyFormat, trackOpens, trackClicks } = req.body ?? {};
6499
6509
  const set = {
6500
6510
  "draft.lastModifiedBy": req.actor,
6501
6511
  "draft.lastModifiedAt": /* @__PURE__ */ new Date(),
@@ -6523,6 +6533,7 @@ function apiRouter(mailer, opts = {}) {
6523
6533
  });
6524
6534
  }
6525
6535
  }
6536
+ if (TEMPLATE_BODY_FORMATS.includes(bodyFormat)) set.bodyFormat = bodyFormat;
6526
6537
  if (typeof trackOpens === "boolean") set.trackOpens = trackOpens;
6527
6538
  if (typeof trackClicks === "boolean") set.trackClicks = trackClicks;
6528
6539
  await c.templates.updateOne({ _id: tpl._id }, { $set: set });
@@ -6608,7 +6619,9 @@ function apiRouter(mailer, opts = {}) {
6608
6619
  fromEmail: tpl.fromEmail,
6609
6620
  replyTo: tpl.replyTo ?? void 0,
6610
6621
  subject: draft.subject,
6611
- html: compiled.html,
6622
+ // Match the real send shape — a text_only template's deliverability
6623
+ // should be scored on the single-part message it actually sends.
6624
+ ...tpl.bodyFormat === "text_only" ? {} : { html: compiled.html },
6612
6625
  text: compiled.plainText,
6613
6626
  headers: {},
6614
6627
  messageMeta: { mailTesterCheckId: checkId }
@@ -6953,7 +6966,9 @@ function apiRouter(mailer, opts = {}) {
6953
6966
  fromName: rendered.fromName,
6954
6967
  fromEmail: rendered.fromEmail,
6955
6968
  subject: `[TEST] ${rendered.subject}`,
6956
- html: tracking.html,
6969
+ // Match the real send shape, or a test of a text_only template would
6970
+ // arrive as HTML and hide exactly what the author is checking.
6971
+ ...tpl.bodyFormat === "text_only" ? {} : { html: tracking.html },
6957
6972
  text: rendered.plainText
6958
6973
  });
6959
6974
  await mailer.audit({
@@ -7593,7 +7608,7 @@ var DEDUPE_POLICIES = [
7593
7608
  ];
7594
7609
 
7595
7610
  // src/server/index.ts
7596
- var VERSION = "0.10.2" ;
7611
+ var VERSION = "0.11.0" ;
7597
7612
 
7598
7613
  export { DEDUPE_POLICIES, FLOW_STEP_KINDS, Mailer, MongoContactAdapter, NullProvider, PREDICATE_KINDS, RESERVED_VAR_KEYS, SEGMENT_FILTER_KINDS, SendGridProvider, VERSION, applyTracking, applyWebhookEvent, compileMailyTemplate, compileTemplate, computeDeliveryTime, createAdminRouter, createPublicRouter, defaultFlowStep, defaultPredicate, defaultSegmentFilter, defineVars, derivePlaintext, dispatchSend, ensureIndexes, getCollections, predicateKind, processNewlyFiredEventTriggers, processOneRunStep, renderTemplate, runTick, sha256Hex, signUnsubscribeToken, sweepStrandedFlowRuns, validateSenderDomain, varsJsonSchema, verifyUnsubscribeToken };
7599
7614
  //# sourceMappingURL=index.js.map