Repository navigation
Description
Summary
An active drip sequence sends nothing. Every enrollment fails in attemptMailSending with footer_render_failed and is retried every ~30s forever. Two bugs combine to cause this.
Bug 1: footer compliance check rejects long single-line mailing addresses
apps/api/src/mail/render.ts (mailingAddressAppearsInText, footer check near line 309) requires each non-empty line of the team's mailing address to appear verbatim in document.body.textContent.
The managed footer renders long addresses with a line break and indentation inside the address (for example after a comma). The raw text then never contains the unbroken address, so the check throws footer_render_failed.
Reproduction (no DB or send needed):
const address = "<any single-line address long enough for the footer to wrap>";
const html = await renderEmailToHtml({
email: content,
blocks: [SENDLIT_FOOTER_BLOCK],
renderContext: { footer: { mailingAddress: address, unsubscribeUrl } },
});
const text = new JSDOM(html).window.document.body.textContent ?? "";
text.includes(address); // false
text.replace(/\s+/g, " ").includes(address); // trueThe unsubscribe href check passes in the same case. The existing multi-line test passes only because the input address is already split by \n.
Impact: every recipient of a team's sequence gets the same footer, so nothing sends for that team until the address is changed.
Suggested fix: collapse whitespace on both the text and each address line before comparing, and add a regression test with a long single-line address.
Bug 2: render failures are never counted, so enrollments retry forever
In automation/process-ongoing-sequence.ts, renderCampaignHtml runs in attemptMailSending before the try block. A render error therefore never increments ongoing_sequences.retry_count and never reaches sequenceBounceLimit. The error propagates, the claim is released, and the row stays due.
Evidence: the stuck enrollment has retry_count = 0 and has been failing for hours. Its logs repeat every ~30s with processOngoingSequence failed and sequence worker failed.
Suggested fix: move the render inside the try (or count render failures explicitly) so repeated failures drop or pause the enrollment.
Acceptance criteria
- A sequence whose team has a long single-line mailing address sends normally.
- A permanent render failure is counted and stops retrying after
sequenceBounceLimitattempts. - Regression tests cover both cases.
🤖 Generated with Claude Code
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
fix(api): pause the send on a permanent render error instead of dropp…