Skip to content
AgencyProofby Intelliblitz

Manual

Seven places a contact form can lose a lead before anyone notices

The form submits, a green message appears, and everyone moves on. That message is evidence about one thing only: what the page displayed. Here is the trace to run instead, and the file you keep when a client asks whether the enquiry ever arrived.

Balaji Ponnambalam10 min read
A brass tube runs diagonally through riveted junction collars, one hinged open and empty. A frog holds a lamp to one collar; below, an empty basket waits under a receiving hatch still shuttered closed.

Thanks. Your enquiry has been sent.

That string lives in a template. A browser painted it because some code took its success branch, and it asserts something the page has no way to observe. The observation is real and the interpretation is narrow: the page displayed a confirmation. It says nothing about a database, a mailbox or a person.

Rendered confirmation, fixture form
Thanks. Your enquiry has been sent.

EstablishesThe page rendered a confirmation string after the submit control was used.

Does not establishThat any system beyond the page received, stored or forwarded the submission.

Between that click and a lead somebody can answer sit seven separable stages. Each is owned by a different party, fails differently, and leaves a different artifact behind. A test that stops at the confirmation has inspected one of them, and not the one that loses enquiries.

StageWhat you doEvidence you keepFailure you would seeWho owns the fix
Browser validationSubmit empty, then with awkward valuesThe value and the message shownA legitimate value refusedMarkup author
Request dispatchWatch the network panelMethod, path, response statusConfirmation after a failed requestFront end
Request handlingFind it in the server logThe handler's own log lineA 200 with an error inside itEndpoint owner
Storage or CRM entrySearch for a marker you plantedRecord identifier and timestampNo row, or a silent mergeIntegration owner
Notification deliveryRead the delivery record, then the mailboxDelivery status and message identifierAccepted by a relay, never in a mailboxSending domain owner
Reply routingReply, and confirm arrivalThe reply, receivedReplies reaching nobodyInbox owner
Audit recordWrite the receipt nowThe receipt itselfAn argument with no file behind itYou
Scroll for more →

No external scanner runs that trace for you, and ours does not try. AgencyProof does not submit forms: form submission is recorded as a check that was not performed, and checkout and payment flows are not attempted. AgencyProof inspects a bounded sample of reachable public pages. The report records the pages and methods used, plus important checks that were not performed.

Watch the browser decide the form is valid

Leave a required field empty and submit. The browser refuses and shows its own message. That refusal is constraint validation, and the HTML Standard is exact about what it reports. On checkValidity(): "Returns true if the element's value has no validity problems; false otherwise. Fires an invalid event at the element in the latter case."

It is a statement about values sitting in controls, evaluated in the page, before anything is dispatched anywhere. A form that passes has established that its own fields satisfy their own constraints, and nothing else has happened yet.

Two failures live here and they point in opposite directions. The loud one is a field that should be required and is not, so an enquiry arrives with no way to answer it. The quiet one is worse: a pattern or a type that refuses a legitimate value. An email rule that rejects a plus sign, a phone rule that rejects a country code. That visitor is stopped here, produces no request, appears in no log, and is invisible to every later stage. You find it only by typing awkward values on purpose.

Watch the request leave the browser

Network panel open, submit, and look for the request. This is where the two kinds of form part company. A form the browser submits natively performs a navigation: the request goes out, and if the handler answers with a redirect the browser follows it to a page the server chose.

POST /enquiry HTTP/1.1
host: fixture.localhost:8787
content-type: application/x-www-form-urlencoded

HTTP/1.1 303 See Other
location: /thanks

That thank you page is better evidence than it looks: it exists because the handler ran and issued the redirect. A confirmation rendered in place by client script is a weaker claim, because it says only that the client took its success branch, and success branches are sometimes written to run whether or not the request succeeded.

So for a scripted form the question is not whether the message appeared. It is what status came back, and what the client does when one does not. Disconnect the network, submit, and watch. If the confirmation still appears, you found the defect before your client did.

Read the handler's own record

Get to the server's own log and find your submission in it. This is the first artifact in the trace that a browser cannot produce.

AgencyProof's contact form writes the whole lead as one structured line before it attempts either storage or email, and the comment above it says why: the lead stays recoverable from server logs even if both of those fail. That line is the handler's testimony about what it received.

The same file carries a warning for anyone who tests forms with an automated filler. A hidden honeypot field is checked before anything else, and when it is filled the action returns success and stores nothing. A bot gets a quiet confirmation. So does a tool that fills every input on the page, including the one no human can see. The confirmation is correct, the absent record is correct, and with a browser as your only instrument the form looks fine. A design choice, not a defect, and the sharpest argument here for reading the log instead of the screen.

Find the row, or find nothing

Search the store for the submission you just made, using a marker you planted rather than your own name. A build reference in the message body works.

Two failures hide here. The first is a write that failed and told nobody. AgencyProof's own action wraps its intake call in a try and catch, records the error, and carries on, because an internal storage failure should not tell a visitor their enquiry did not go through when the notification path may still have carried it. It also means the visitor's screen cannot be evidence of the write, which is the point.

The second is deduplication. Submit twice from the same address and a CRM may merge the second into the first, leaving no new record and no error. Testing repeatedly with your own address is how most people never see this. Vary the address.

Follow the notification past the send call

A send call that returns without error means the sending library got an answer it liked. Here is that answer, from the fixture's mail catcher:

2026-07-14T09:12:44Z fixture-mta out: to=<studio@fixture.test>
  relay=mx1.fixture.test[203.0.113.10]:25 dsn=2.0.0
  stat=Sent (250 2.0.0 Ok: queued as 4Wm1kP3xyz)

RFC 5321 is explicit about what that acceptance transfers: "once the server has issued a success response at the end of the mail data, a formal handoff of responsibility for the message occurs: the protocol requires that a server MUST accept responsibility for either delivering the message or properly reporting the failure to do so."

Responsibility, not arrival. The same specification separates a delivery system, which passes mail to a user agent or a message store, from a relay system, which transmits it onward to another server. The host that said 250 may have been relaying, and the word queued in that log line says as much.

Authentication policy is the next place a message goes quiet. Under DMARC, a domain publishing p=quarantine asks receivers to treat failing mail as suspicious, which the specification says "can mean 'place into spam folder', 'scrutinize with additional intensity', and/or 'flag as suspicious'". And the receiving side keeps its discretion either way: receivers "MAY choose to reject or quarantine email even if email passes the DMARC mechanism check."

So the evidence here is neither the send call nor the 250. It is the sending provider's own delivery record for that message, and then the mailbox. AgencyProof's notification path opens a row in a delivery ledger before calling the provider and finalises it as sent or failed afterwards. It never throws, and returns false when no provider key is configured. The action above it fails the form only when neither storage nor notification succeeded, so a visitor can see a confirmation while the notification that would have told a human never left. All of that is intentional, and it is exactly why the ledger row is the artifact rather than the screen.

Inspection ticket
High priorityConversion

Enquiry notification never left the sending domain

FILED ON · /contact

Fixture run: the handler stored the enquiry and the page rendered its confirmation. The delivery ledger recorded the same message as failed against an unverified sender. Evidence: the ledger row and the provider's rejection string. Nobody received the enquiry, and nothing on the visitor's screen said so.

A notification path that goes nowhere is the archetypal launch blocker: high consequence, invisible to anyone looking at the site, settled by one observation. Whether it blocks a particular launch is a call somebody has to make, and agreeing that test before the findings arrive keeps it from becoming an argument.

Reply to the message you just sent

Open the notification, reply to it as if you were answering the lead, and confirm the reply arrived.

This is the stage everyone skips, and the one that loses an enquiry after it has already been delivered. AgencyProof's notification sets a reply address only when the submitted value matches a basic address pattern; otherwise a reply goes back to the brand address that sent the alert. The same outcome arrives elsewhere by other routes: an inbox rule that archives anything from the sending domain, an alias that expands to somebody who left, a no-reply sender a reply cannot reach. Thirty seconds of work, and the only way to establish that the loop closes rather than merely starts.

Write the receipt while the tabs are open

Every field on the receipt is cheap now and expensive to reconstruct later.

  • Form and page. Which form, at which URL, on which build reference.
  • Run at. Date and time, with the timezone.
  • Observed result. What you saw at each stage, in the words of the evidence rather than a verdict: 303 to /thanks, record 8841 at 09:12:44Z, delivery record: sent.
  • Destination. Where the submission ended up, named exactly. The store and table, the CRM object, the mailbox address. Not "the team".
  • Owner. A person, with a role, per destination. An unowned destination is the same as no destination.
  • Not established. Spam placement for other recipients, behaviour under load, anything you could not sign in to check.
  • Retest evidence. The date the trace runs again, and against which build. A receipt with no retest date describes a moment, not a system.

Fill in the evidence column of the trace table and you have the body of it.

Keep the file where the argument will happen

Three weeks after launch somebody says the form has never worked. What settles that conversation is not memory and not the confirmation screen.

Question the client will askSettled by the success messageSettled by the traceSettled by neither
Did the page respond?YesYes
Did the request reach the server?NoYes
Was my enquiry stored?NoYes
Did anyone get a notification?NoYes
Inbox rather than spam?NoFor the recipient testedFor every recipient, later
Can we reply to the sender?NoYes
Was it working last Tuesday?NoOnly if run then
Scroll for more →

The fourth column is the honest one. A trace establishes what happened on one run, for the recipients you tested, on the build you tested. It does not establish that the path still holds, which is why the retest date is a field rather than a nicety.

File the receipt where the argument will happen: with the launch record the client received, not in the tester's notes. A receipt somebody else can find without asking you is worth more than a thorough one only you know about.

Provenance

Written by
Balaji PonnambalamFounder, AgencyProof
Technical review
Written and self-reviewed against the codebaseAgencyProof is a one-person engineering team; there is no second reviewer to claim.
Published
Evidence basis
Examples in this article are synthetic fixtures built for the explanation.

Every product claim in an article is checked against the AgencyProof source tree before publication, and traced to the code path that implements it. Where the article describes a method rather than a shipped behaviour, it says which it is.

A dispatch room at night: a corded parcel with an unstruck seal waits on a workbench under one hanging lamp, beside a closed iron dispatch hatch, with a run of small cabinet doors standing open along the left wall.Launch Manual
Manual5 min read

What to inspect before sending a website to the client

The best time to find a defect is before the client's attention shifts from the design to the mistake. A one-hour inspection for the first “finished” link.

By Balaji Ponnambalam