Getting the verification link out of an email (and why click tracking breaks it)

Updated October 16, 2026 · Zyntra

Pick the verification link by its text or its path, never by position in the email, and make sure the URL you get is the real one. If your provider's click tracking is on, every link points at the provider's redirect domain instead of your app: turn tracking off for staging, or follow the redirect once to read the target.

Where links hide in an email

A transactional email usually has an HTML part and a plain-text part. The HTML has the button (<a href>) and often a fallback "copy this URL" line; the text part has the URL written out. Logos, footers and unsubscribe links add more. A typical sign-up email has five to ten links, so "the first link" is a guess that breaks the day marketing adds a logo.

Choose by meaning instead: the anchor text ("Confirm email") or the path (/verify, /auth/callback). Check that exactly one link matches, so a template change fails loudly.

pick-link.ts
type Link = { url: string; text: string };

export function pickLink(links: Link[], test: (l: Link) => boolean): string {
  const found = links.filter(test);
  if (found.length !== 1) {
    throw new Error(`Expected 1 matching link, got ${found.length}: ${
      links.map((l) => l.url).join(", ")
    }`);
  }
  return found[0]!.url;
}

// pickLink(email.links, (l) => new URL(l.url).pathname === "/verify")

Parsing HTML yourself: the traps

  • Entities. In HTML, & in a URL is written &amp;. A regex over raw HTML returns ?a=1&amp;b=2, which your app may not accept. An HTML parser decodes it.
  • Quoted-printable. If you read the raw MIME message, long lines are wrapped with = at the end and =3D stands for =. Decode the part before searching.
  • Duplicates. The same URL in the button and in the text part. Deduplicate by URL.

Click tracking rewrites every link

Providers measure clicks by replacing each URL with one on their own domain that redirects to yours. SendGrid's click tracking "rewrites all the links and URLs in your emails" (plain-text emails only if you opt in). Postmark's link tracking replaces links with ones on click.pstmrk.it. The test then sees a tracking URL: the path check fails, and visiting it registers a click in your provider's stats.

Three ways out, best first:

  • Turn tracking off for staging. In Postmark, TrackLinks is set per server or per message (None is the default). In SendGrid, tracking is an account setting, and the mail send API takes tracking_settings.click_tracking per message.
  • Turn it off for transactional streams only. Sign-up and reset emails rarely need click stats, and users see the real URL.
  • Follow the redirect once and read the target without opening it in the browser:
resolve-tracked.ts
// Note: this request counts as a click in your provider's stats.
export async function resolveTracked(url: string): Promise<string> {
  const res = await fetch(url, { redirect: "manual" });
  return res.headers.get("location") ?? url;
}

Questions

Should the test check the link's domain?
Yes. A staging email that links to production is a real bug, and asserting the host catches it before a user does.
The link works in the browser but not in my test. Why?
Usually an &amp; left in the URL, or a tracking redirect the test did not follow. Log the exact URL the test used and compare.