Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions lib/outreach/cold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,48 @@ const INTERNAL = /@(profullstack\.com|crawlproof\.com)$/i;
* excludes all role accounts because it mails people who opted in personally;
* this list is deliberately narrower.
*/
/**
* Mailboxes that must never receive cold outreach.
*
* Not a deliverability heuristic — these are addresses where an unsolicited
* pitch is actively harmful. Writing to an opt-out inbox is the opposite of
* what it exists for; writing to a data-protection officer hands a complaint
* to the one person whose job is filing them; writing to an accessibility or
* accommodations queue takes time from people who need it.
*
* Every entry below was added because a real send reached it. `optout` and
* `dpo` were missed by the original list even though `unsubscribe`, `privacy`
* and `legal` were on it — near-synonyms are not covered by intent, only by
* enumeration, so the list errs toward listing variants. `accomodation` is
* the common misspelling and is deliberately included; the address that
* prompted it was spelled that way.
*/
const NEVER_CONTACT_LOCALPART =
/^(noreply|no-reply|donotreply|do-not-reply|mailer-daemon|postmaster|abuse|dmca|security|privacy|legal|unsubscribe|bounce|bounces)$/i;
new RegExp(
"^(" +
[
// Automated senders — nobody reads these.
"noreply", "no-reply", "donotreply", "do-not-reply", "mailer-daemon",
"postmaster", "bounce", "bounces",
// Opting out. Mailing these is backwards.
"unsubscribe", "optout", "opt-out", "remove", "removeme", "no-contact",
// Reporting and enforcement.
"abuse", "dmca", "security", "fraud", "phishing", "spam", "complaints",
"whistleblower", "ethics",
// Data protection. A cold pitch here is a complaint waiting to happen.
"privacy", "legal", "compliance", "dpo", "gdpr",
"dataprotection", "data-protection",
// Accessibility and accommodations — queues for people who need them.
"accessibility", "a11y",
"accommodation", "accommodations", "accomodation", "accomodations",
// Hiring queues. Wrong target for a pitch, and wrong target for a
// recruiting pitch too — you are writing to a rival's applicants.
"careers", "jobs", "recruiting", "recruitment", "hr", "talent",
"candidates", "applications", "admissions",
].join("|") +
")$",
"i",
);

/** Ranked best-first. A named human beats a shared inbox beats a department. */
const ROLE_PREFERENCE = [
Expand Down Expand Up @@ -81,7 +121,19 @@ export function domainOf(email: string): string {
}

export function isNeverContactMailbox(email: string): boolean {
return NEVER_CONTACT_LOCALPART.test(localPart(email));
const local = localPart(email);
if (NEVER_CONTACT_LOCALPART.test(local)) return true;
// Compound localparts have to be checked token by token: an exact match
// alone lets `candidate-accomodations` through while blocking
// `accomodations`, which is how a real accessibility queue got mailed.
//
// Splitting only on separators is what keeps this from over-blocking —
// `privacyengineering` and `hrothgar` stay one token and stay contactable,
// where a substring match would have refused both.
return local
.split(/[-._+]/)
.filter(Boolean)
.some((token) => NEVER_CONTACT_LOCALPART.test(token));
}

/**
Expand Down
97 changes: 97 additions & 0 deletions tests/never-contact.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { describe, it, expect } from "vitest";
import { isNeverContactMailbox, rankContacts, suppressionReason } from "@/lib/outreach/cold";

// Every address in this first list actually received a live cold email before
// the guard covered it. They are kept verbatim rather than paraphrased,
// because the failure was that near-synonyms of listed words were not listed:
// `unsubscribe`, `privacy` and `legal` were all present while `optout` and
// `dpo` were not, and intent does not close that gap — enumeration does.
describe("addresses that leaked through and must not again", () => {
const leaked = [
"optout@dribbble.com",
"dpo@ecoconsult.it",
"candidate-accomodations@activisionblizzard.com",
];

for (const email of leaked) {
it(`never contacts ${email}`, () => {
expect(isNeverContactMailbox(email)).toBe(true);
});
}
});

describe("categories that must never receive cold outreach", () => {
const blocked = [
// Opting out — mailing these is backwards.
"unsubscribe@example.com",
"opt-out@example.com",
"removeme@example.com",
// Data protection — a pitch here goes to whoever files the complaint.
"privacy@example.com",
"gdpr@example.com",
"data-protection@example.com",
"compliance@example.com",
// Reporting and enforcement.
"abuse@example.com",
"phishing@example.com",
"whistleblower@example.com",
// Accessibility queues, including the common misspelling.
"accessibility@example.com",
"accommodations@example.com",
"accomodations@example.com",
"a11y@example.com",
// Automated senders.
"noreply@example.com",
"mailer-daemon@example.com",
"bounces@example.com",
// Hiring queues.
"careers@example.com",
"recruiting@example.com",
"admissions@example.com",
];

for (const email of blocked) {
it(`blocks ${email}`, () => {
expect(isNeverContactMailbox(email)).toBe(true);
});
}

it("reports it as a suppression reason, not a silent drop", () => {
expect(
suppressionReason({ email: "optout@example.com", suppressed: false }),
).toBe("never-contact-mailbox");
});

it("filters them out of ranked contacts entirely", () => {
const ranked = rankContacts([
{ email: "optout@example.com", source: "mailto", sameDomain: true },
{ email: "jane@example.com", source: "mailto", sameDomain: true },
]);
expect(ranked.map((c) => c.email)).toEqual(["jane@example.com"]);
});
});

describe("addresses that are still fair game", () => {
// Over-blocking costs real prospects. A shared business inbox is often the
// only address a small company publishes, and is a legitimate B2B target —
// unlike anything in the list above.
const allowed = [
"hello@example.com",
"info@example.com",
"contact@example.com",
"support@example.com",
"sales@example.com",
"jane.doe@example.com",
"j.smith@example.com",
// Contains a blocked word but is not that mailbox.
"privacyengineering@example.com",
"careerscoach@example.com",
"hrothgar@example.com",
];

for (const email of allowed) {
it(`allows ${email}`, () => {
expect(isNeverContactMailbox(email)).toBe(false);
});
}
});
Loading