Skip to content
GDPR compliant. Hosted in DE.
14-day free trial →
MonitoringDeliverabilityConsent
Monitoring 14 min read 22 Sept 2026

Monitoring Double Opt-In: When Confirmation Mail Stalls

The confirmation flow breaks quietly: the form answers, the mail stalls, nobody complains. Five measuring points, matching deadlines and the evidence that consent requires.

X

XICTRAQ

XICTRAQ

Double-Opt-InDeliveryConsent
0.3 %
upper limit for the spam rate reported in Postmaster Tools (Gmail)
30 min
recommended minimum interval between two delivery attempts (RFC 5321)
4-5 days
minimum give-up time of a mail server before it stops (RFC 5321)
Confirmation flow: five stations, five measuring pointsExample view of a monitored double opt-in signup1Form submittedResponse time and status codechecked2Record createdToken and timestamp storedchecked3Mail handed overAccepted by the mail serverchecked4Delivery confirmedResponse from the mailboxopen5Confirmation clickStatus switches to confirmedno signalAlert deadlines per stationForm does not answer1 minMail not handed over5 minDelivery still open30 minConfirmation missing24 hThe long deadline follows the retryrhythm of the mail servers, not thewishes of the sender.Measuring points: form response, record, mail handover, delivery, confirmation click
A newsletter signup consists of two halves, and only the first one is visible. The second runs through a sending path, a mailbox you do not control and a click that may arrive days later or not at all. When it fails, hardly anyone reports it: whoever did not receive the confirmation mail does not know it was supposed to arrive. Legally, this stretch is exactly where consent comes into being and where it is documented. Article 7(1) GDPR requires the controller to be able to demonstrate consent (GDPR), and Section 7(2) no. 2 of the German Act Against Unfair Competition treats advertising by electronic mail without prior express consent as an unreasonable nuisance (UWG). This article describes where the flow tears, which five measuring points cover it, which deadlines match the retry rules of mail servers, and what has to remain of a signup so that it still works as evidence two years later.

Why the confirmation flow deserves its own measuring point

From an operations point of view a signup is a process with a single visible result: the form answers, the visitor sees the notice about the confirmation mail, the counter goes up by one. Everything after that happens outside your own site. The message enters a queue, moves from there to a sending path, and from there to a mailbox that may accept it, delay it or sort it out. If it stalls on the way, that produces no error page and no entry in the website error log. The process looks successful on both ends although it broke in the middle. How the visible part of such a chain can be checked is described in the article Monitoring contact form delivery; the confirmation flow attaches a second, considerably longer half to it.

This second half carries the legal weight of the whole process. Under Article 4 no. 11 GDPR, consent is any freely given, specific, informed and unambiguous indication of the data subject's wishes by which they signify agreement through a statement or a clear affirmative action (GDPR). Recital 32 of the Regulation states explicitly what does not qualify: silence, pre-ticked boxes or inactivity should not constitute consent (GDPR). Article 7(1) requires the controller to demonstrate that consent was given (GDPR), and Article 5(2) turns this into a general accountability duty (GDPR). The click on the confirmation link is the affirmative action this chain calls for, and at the same time the point at which the evidence either comes into being or fails to.

  • Section 7(2) no. 2 UWG: Advertising using electronic mail without prior express consent of the addressee counts as an unreasonable nuisance (UWG).
  • Article 4 no. 11 GDPR: Consent is a freely given, specific, informed and unambiguous indication of wishes in the form of a statement or a clear affirmative action (GDPR).
  • Recital 32 GDPR: Silence, pre-ticked boxes or inactivity of the data subject should not constitute consent (GDPR).
  • Article 7(1) GDPR: The controller must be able to demonstrate that the data subject has consented (GDPR).
  • Article 5(2) GDPR: The controller is responsible for compliance with the principles and must be able to demonstrate it, the so-called accountability duty (GDPR).
  • Article 7(3) GDPR: Withdrawing consent must be as easy as giving it (GDPR).

Between a signup and a demonstrable signup lies exactly one delivered and clicked message. Anyone who only evaluates the number of submitted forms is measuring intent rather than outcome. The gap between those two numbers is the actual key figure of this flow, and it behaves differently from a form abandonment rate: abandonment inside the form happens in front of the visitor and can be traced through field-level analysis, as described in the article Reducing form abandonment with form analytics. Abandonment in the confirmation flow happens inside someone else's mailbox and leaves no trace on your own site.

Where the flow typically tears

The flow consists of five stations, and each of them can fail on its own without disturbing the others. First, the form accepts the input and answers with a status code. Second, the application creates a record with a token, a timestamp and the wording of the consent. Third, it hands the message over to the sending path, which accepts or rejects it. Fourth, the recipient's mail server delivers, delays or rejects for good. Fifth, the recipient clicks the link and the status switches to confirmed. Monitoring that only checks the first station reports green as long as the form answers, even when no confirmation at all has arrived for days.

The most frequent tears are in the middle. A worker process that drains the queue and was not restarted after a release keeps accepting jobs and processes none of them. An access key for the sending path expires, and every handover acknowledges an error nobody reads. A changed sender address falls out of authentication and lands in the spam folder. A subject line that lost its character encoding during a migration looks like data garbage in the mailbox and gets deleted unread, a failure pattern the article Finding broken umlauts after a migration shows in other places. And the confirmation link itself may have expired before the recipient next opens their mailbox.

When security software opens the link before the recipient does

Security products and mailbox services fetch addresses from messages in advance in order to inspect them. RFC 8058 names exactly this behaviour as the reason for its rules: mail software sometimes fetches URLs in mail header fields and thereby accidentally triggers unsubscriptions (RFC 8058). For links in the message body this is not standardised, but the mechanics are the same. A confirmation link that sets the status on a simple fetch can be confirmed by a machine. In the evaluation this looks like a very fast confirmation, seconds after dispatch and often from a data centre network. Anyone who wants to rule this out lets the link lead to a page that requires a second, explicit action, and evaluates confirmations arriving within a few seconds separately.

The five measuring points

Five stations produce five measuring points, and they do not all sit in the same area of responsibility. The first two belong to your own application, the third to the handover to the sending path, the fourth to a foreign system and the fifth again to your own application. Usable monitoring reflects this distribution instead of laying a single check across the whole chain. Only if the failure of a station can be named does the alert lead to an action rather than to a search.

  1. Form response: The signup path is walked in a real browser until the page with the notice about the confirmation mail appears. Status code, response time and the presence of the notice text are measured. A form that answers with status code 200 while displaying an error message shows up only in this check.
  2. Record: After the signup, an entry exists with a token, a timestamp, an origin and the wording of the consent. The check confirms that the entry was created and that its status is pending. If it is missing, the application accepted the input and discarded it.
  3. Handover to the sending path: The sending service acknowledges acceptance with an identifier. This acknowledgement is the first hard proof that the message left your own system. Without it, the job is sitting in the queue, and then the length of that queue is the value that has to be measured.
  4. Delivery: The recipient's mail server accepts, delays or rejects. Temporary rejections with a status code in the 4xx range are part of normal operation and get retried, final rejections in the 5xx range are not. A rising number of final rejections points, in our experience, to a problem with authentication or the sender address rather than to wrong recipient addresses.
  5. Confirmation click: The status switches from pending to confirmed. This switch is the only measuring point that evidences an action by a human being, and the only one that carries the demonstration required by Article 7(1) GDPR (GDPR).

The first and the fifth point can be checked from outside: both are addresses on your own website and can be walked with a browser check. Points two to four sit on the inside and need either an interface that reports the state or a signal that the application sends of its own accord. Neither is much effort. An endpoint returning the number of open signups, the age of the oldest open signup and the length of the sending queue covers points two and three. For point four, evaluating the responses of the sending path is sufficient in many cases.

Test signups belong in a separate record set

A monitored flow needs regular test signups, and each of them creates a record with an address behind which there is no person. Such entries must not enter the mailing list, the confirmation rate or the export. What works well is a fixed marker on the record, a dedicated mailbox for the check and a cleanup run that removes test entries after a few days. For drafts and documentation the usual rule applies: invented addresses belong on a domain that demonstrably belongs to nobody, for example signup@example.invalid.

Check intervals and the deadlines behind them

An interval answers the question of how often something is measured. A deadline answers the question of when a deviation becomes an incident. In the confirmation flow the two are far apart, because one part of the chain is slow by nature. The form path can be checked every minute; whether a confirmation is missing can be judged at the earliest after a deadline that matches the retry rules of mail servers. Treating both as the same thing produces either false alarms or a detection that arrives two days late.

Measuring pointCheck intervalAlert when
Signup path in the browserhourlyconfirmation page or notice text is missing
Page behind the confirmation linkevery 5 minutesstatus code or response time deviates
Sending queueevery 5 minutesoldest unprocessed message is older than 10 minutes
Heartbeat of the sending workerexpected every 5 minutessignal stays away for 15 minutes
Acknowledgements from the sending pathevery 15 minutesfinal rejections rise compared with the previous week
Share of confirmed signupshourlyshare falls below the line of the same hour of the previous week
Oldest open signuphourlyage exceeds the configured confirmation deadline
Authentication of the sender domaindailySPF, DKIM or DMARC is missing or invalid

The deadline in the second-to-last row is the only value in this table that cannot be chosen freely without ignoring the technology behind it. Why it sits in the order of hours rather than minutes is explained further down in the section on retry rules. Everything else is a question of operations: a mailing list that receives two signups a month does not need an hourly rate evaluation but a check that fires when the single signup of the week stays unconfirmed.

What the flow can be monitored with

Four types of check together cover the five measuring points. None of them is new in itself, the combination is: the browser takes the visible ends, the interface check takes the handover, the heartbeat takes the silent worker process and the alerting takes the deadline.

Signup path in a real browser

Browser monitoring fills in the signup form with a test address, submits it and waits for the page with the notice about the confirmation mail. The path runs with JavaScript, consent layer and session data, that is, under the same conditions as for a visitor.

Confirmation page as its own check

The page behind the confirmation link is a separate address and deserves a separate check. API monitoring calls it with an invalid token and expects the intended error page. If it answers with a server error, the flow has torn on the last metre.

Silent sending worker with a heartbeat

The process that drains the queue reports after every run through heartbeats. If the signal stays away, that gets reported instead of surfacing the next morning as a pile of unsent messages.

Two deadlines instead of one instant alert

Alerting carries two different deadlines on this flow: a short one for the form path and a long one for the missing confirmation. Both go to the same on-call rotation, but only the short one justifies a phone call in the middle of the night.

What cannot be mapped this way is the route inside the foreign mailbox. Whether a message sits in the inbox or in the spam folder is invisible to the sender. The approximation for it is the share of confirmed signups over time: if it falls without anything having changed in the form and in the text of the message, the cause lies with some probability in delivery. That is not a measurement but an indication, yet an indication that arrives early enough to check authentication.

Calculating the confirmation rate correctly

The share of confirmed signups looks like a simple division and is nevertheless regularly wrong for the current hour. Anyone who divides all signups of a period by all confirmations of the same period counts signups whose confirmation is not even due yet. The rate of the last hour then sits structurally low, the rate of the previous day recovers on its own, and an alert on this value fires every evening. The calculation therefore needs a maturity period: only what is older than the deadline within which a confirmation is expected gets counted.

clicked-share.js
// Share of clicked signups: only mature cases are counted.
// A signup is mature once its confirmation deadline has passed.
function clickedShare(signups, deadlineHours, now = Date.now()) {
  const deadline = deadlineHours * 3600 * 1000;
  const mature = signups.filter((s) => now - s.createdAt >= deadline);

  if (mature.length === 0) return null;   // no measurement, not 0

  const open = mature.filter((s) => s.clickedAt === null);
  const clicked = mature.length - open.length;

  return {
    population: mature.length,
    clicked,
    share: clicked / mature.length,
    openMaxDays: open.length
      ? Math.max(...open.map((s) => (now - s.createdAt) / 86400000))
      : null
  };
}

Two values fall out of this, and both belong on the dashboard. The share shows whether the flow carries overall; the age of the oldest open signup shows whether it is stalled right now. The second value reacts faster: if sending stalls, it grows steadily from the first open signup onwards, while the share only tips once enough cases have passed the deadline. An alert on the age of the oldest open signup is therefore usually the more usable first stage, and the share the second, slower confirmation of the same fault.

A confirmation mail that nobody misses is the quietest failure in the stack. It costs no error page, no phone call and no complaint, only every consent that should have come into being during that time.

— XICTRAQ

What the mailbox providers require

Technically, the confirmation mail is a message like any other and falls under the same rules as the mailing list it opens access to. Since 1 February 2024, Google requires all senders sending to Gmail accounts to meet a catalogue of requirements (Gmail); anyone sending more than 5,000 messages per day to Gmail accounts has additionally fallen under an extended section since the same date (Gmail). What follows from this for ongoing sending is set out in the article Deliverability rules for bulk email. For the confirmation flow, four points matter most.

  • Complaint rate below 0.3 percent: For the spam rate reported in Postmaster Tools, Google names an upper limit of 0.3 percent (Gmail). Confirmation mails are marked as unwanted less often than a mailing list, but they count towards the same rate.
  • Authentication of the sender domain: SPF, DKIM and DMARC belong in place and monitored before the mailing list grows. The procedure is described in the article Setting up SPF, DKIM and DMARC; what gets monitored is not only whether the records exist but whether they match the address actually sending.
  • One-click unsubscribe: For marketing and subscribed messages, Google requires one-click unsubscribe plus a clearly visible unsubscribe link in the message body in the section for senders of more than 5,000 messages per day (Gmail). Technically, RFC 8058 describes a List-Unsubscribe-Post header field with the value List-Unsubscribe=One-Click for this (RFC 8058).
  • Reputation of the sending address: If the IP address or the domain of the sending path is on a blocklist, the confirmation mail is hit first, because it goes to a mailbox that does not know the sender yet. How this can be checked continuously is described in the article Blacklist monitoring for email deliverability.
DMARC reports are the feedback you otherwise do not get

As a rule, the sender does not learn from the mailbox provider why a message was sorted out. The regular feedback available for this is mainly the aggregate DMARC reports: they show, per sending address range, how many messages passed the SPF and DKIM checks and how many did not. That is exactly where it becomes visible when the sending path for the confirmation mail is a different one from the path for the mailing list and only one of the two is properly aligned. How to read these reports is described in the article Analysing and understanding DMARC reports.

Checking the flow from outside

Before monitoring is set up, a look from outside with simple means is worthwhile. Four calls are enough to establish whether the flow answers at the intended places at all: the form, the state endpoint, the authentication of the sender domain and the page behind the confirmation link. The addresses in the following example sit on a domain that demonstrably belongs to nobody.

$ curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' -X POST -d 'email=check@example.invalid&consent=1' https://www.example.invalid/newsletter/signup
200 0.412
$ curl -sS https://www.example.invalid/api/signups/state
{"open":14,"oldestOpenMinutes":9,"queue":0,"lastDispatch":"2026-09-22T08:41:07Z"}
$ dig +short TXT _dmarc.example.invalid
"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.invalid; adkim=s; aspf=s"
$ curl -sSI 'https://www.example.invalid/newsletter/confirm?token=invalid' | head -3
HTTP/2 410 cache-control: no-store content-type: text/html; charset=utf-8

The last call is the most revealing one. An expired or invented token should produce a designed page with a clear message, not a server error and not an empty page with status code 200. The second call also shows how little it takes to make the inner stations measurable from outside: three numbers and a timestamp. If this endpoint is fed by an external sending service, it is worth watching whether its interface announces a retirement; how that can be detected automatically is described in the article Monitoring sunset and deprecation headers.

An alert without a matching deadline is a false alarm

Set up two separate alerts before fine-tuning any thresholds: a short one on the form path that fires within minutes, and a long one on the oldest open signup that matches the retry rules of mail servers. The short one runs through browser monitoring and detects a broken signup path before it costs a day of signups. The long one detects the quiet case in which the form works and only the confirmations fail to arrive.

Why delivery takes time

A mail server that cannot get rid of a message right away does not throw it away but tries again. RFC 5321 recommends at least 30 minutes between two attempts and points out at the same time that a more refined strategy is beneficial when the reason for non-delivery is known (RFC 5321). For monitoring this means: a confirmation mail that is not in the mailbox after ten minutes is not an incident but a normal intermediate state. An alert on this state produces a notification nobody can act on, and trains the on-call rotation to skip notifications of that kind.

At the other end sits the give-up time. According to the same passage in RFC 5321, retries continue until the message is transmitted or the sender gives up, with the give-up time generally needing to be at least four to five days (RFC 5321). Two decisions follow from this. First, the confirmation link should stay valid considerably longer than that span, otherwise it expires while the message is still in transit. Second, the alert deadline for missing confirmations belongs in the order of hours up to one day: short enough to notice a stalled dispatch on the same working day, long enough not to report the normal retry as a fault.

What has to remain documented

Monitoring that notices the failure does not replace documentation of what worked. Article 7(1) GDPR requires demonstrating consent (GDPR), Article 5(2) turns this into the controller's accountability duty (GDPR). In practice this means the record has to describe the process in such a way that it remains comprehensible years later without knowledge of the system of the time. What gets stored for this belongs in the record of processing activities and in the privacy notice; the following list is a technical recommendation and does not replace legal advice.

  • Time of the signup and of the confirmation, each with a time zone and in machine-readable form.
  • The wording of the consent, not just a reference to the page. The text changes, the record should hold the state at the time of the signup.
  • The identifier of the form and of its version, so that it can later be attributed which version was actually shown to the visitor.
  • The identifier of the sent confirmation mail including the acknowledgement of the sending path, so that the route between signup and click is demonstrable.
  • Origin data to the extent covered by your own privacy notice, for example a truncated IP address. What is not announced is not stored either.
  • Withdrawal and unsubscribe with time and route, because otherwise the stack only knows the granting and not the end of the consent.
The way back belongs to the same flow

Article 7(3) GDPR requires that withdrawing consent is as easy as giving it (GDPR). In practice this means an unsubscribe that works without signing into an account and without an additional query, and an unsubscribe path that is monitored just like the signup path. Otherwise a broken unsubscribe page surfaces even later than a broken confirmation page. If sending runs through a service provider, the corresponding data processing agreement belongs in the same consideration; which duties have to be checked continuously as a result is described in the article Monitoring data processing agreements under Article 28.

Rolling it out in two weeks

In the first week the measurement basis is created. This includes a state endpoint returning the number of open signups, the age of the oldest open signup and the length of the sending queue, a heartbeat from the process that drains the queue, and a test address in a dedicated mailbox. In parallel, the signup path is walked once completely by hand while recording how long each step takes. This measurement supplies the number from which the confirmation deadline is derived later, instead of estimating it.

In the second week the checks are set up and the deadlines are configured: browser check on the signup path, interface check on the state endpoint and the confirmation page, heartbeat with an expectation, two alert stages with different deadlines. Finally the chain is deliberately broken once, for example by stopping the worker process, and it is verified that the alert arrives and that somebody picks it up. Anyone touching the signup path anyway should check the consent layer of the page in the same pass, because it technically affects the signup path; how to implement it cleanly is described in the article Implementing cookie consent correctly.

Sources and studies

This article draws on: Section 7 of the German Act Against Unfair Competition (Gesetze im Internet), Regulation (EU) 2016/679 (Articles 4, 5 and 7 as well as Recital 32), RFC 5321 (Simple Mail Transfer Protocol, section 4.5.4.1), RFC 8058 (Signaling One-Click Functionality for List Email Headers) and Google's sender guidelines for Gmail. The legal provisions are wordings without interpretation, the mailbox provider requirements are values as of a given date and may change; the values from RFC 5321 are recommendations of the standard, not assurances by individual operators. Every number in this article is shown with its source.

How long should a confirmation link stay valid?
Considerably longer than the time a message can be in transit. RFC 5321 states that the give-up time of a mail server generally needs to be at least four to five days (RFC 5321); a link that expires after 24 hours can therefore run out while the message is still being delivered. More important than the exact duration is what happens after expiry: the page should offer a new confirmation mail instead of an error message.
When does a missing confirmation become an incident?
As soon as the age of the oldest open signup exceeds a deadline derived from your own history. As a rule this deadline sits at several hours up to one day. In our experience, individual signups stay open permanently because the recipient does not click the link; that is not an incident. An incident exists when no confirmation at all arrives over a longer period although signups keep coming in.
What to do when the confirmation rate suddenly falls?
Check in this order: did the handover to the sending path succeed, are there acknowledgements? Is the number of final rejections rising? Do SPF, DKIM and DMARC still match the address actually sending? Have the sender name, the subject line or the text changed? Only after that is a look at blocklists worthwhile. A drop without a technical change points, in our experience, to delivery, a drop immediately after a release to your own system.
Does a confirmation arriving seconds after dispatch count?
It should at least be looked at separately. Security software and mailbox services fetch addresses from messages in advance; RFC 8058 describes exactly this behaviour as the reason why unsubscriptions get triggered accidentally through a header field (RFC 8058). A confirmation a few seconds after dispatch, on top of that from a data centre network, is therefore not solid proof of an action by a human being. Anyone who wants to rule this out requires a second, explicit action on the confirmation page.
Does a contact form need double opt-in as well?
As a rule, no. Section 7(2) no. 2 UWG concerns advertising using electronic mail without prior express consent (UWG); the answer to an enquiry is not advertising. As soon as a mailing list is filled from the contact form, the situation changes, and then the same requirement applies as for the newsletter. This classification is technical orientation and does not replace legal advice.
What has to be stored to demonstrate consent?
Article 7(1) GDPR requires that the controller be able to demonstrate that consent was given (GDPR). In practice this demonstration is carried by the time of the signup, the time of the confirmation, the wording of the consent in the version valid back then, and the identifier of the sent confirmation mail including the acknowledgement of the sending path. Origin data such as a truncated IP address only to the extent announced by your own privacy notice.
Start in 60 seconds

Let XICTRAQ watch your website.

Permanent free plan available. No credit card, no installation, no hidden fees.