Defaults.Exposed

'may be forged' in your headers is a reverse DNS problem, not a spoofing alert

You opened the raw headers on a message, found a line with “(may be forged)” in it, and concluded that somebody is spoofing your domain, or that your own mail is failing a check. The receiving mail server writes that string for a different reason: it looked up the connecting IP address in reverse DNS and couldn’t confirm the answer. It’s a comment about one IP’s PTR record, made before the message body has even arrived, and the record that fixes it lives with whoever owns that IP.

Where the string comes from

Sendmail introduced the phrase, and mail servers descended from it kept it. When a connection arrives, the server takes the client IP, does a reverse lookup to get a name, then looks that name up forwards and checks whether the original IP is among the results. If both steps agree, the server writes the name into the Received header and moves on.

If the reverse lookup returns a name whose forward records don’t include the IP, sendmail appends “(may be forged)” to that name. If the reverse lookup returns nothing at all, there’s no name to annotate and the header carries only the bracketed IP.

Sendmail exposes the same result to its rule sets as the ${client_resolve} macro, which takes one of four values: OK, FAIL, FORGED or TEMP. The header annotation is the FORGED case written out in words for a human. A programmer chose the word to describe a lookup mismatch, at a point in the code where the message itself hasn’t been read yet.

Reading the line field by field

The line looks like this on a message that triggered it:

Received: from mail.yourdomain.example (host-5-113-0-203.static.isp.example [203.0.113.5] (may be forged))
        by mx.receiver.example (8.17.1/8.17.1) with ESMTPS id 486Bq2Xp012345
        for <[email protected]>; Sat, 6 Sep 2026 11:52:02 +0000 (UTC)

The first name, mail.yourdomain.example, is whatever the sending server said in its HELO or EHLO command, and the receiver copies it in without checking it. The name in brackets, host-5-113-0-203.static.isp.example, is what the PTR record for 203.0.113.5 returned. The receiver then looked up an A record for that ISP name, didn’t get 203.0.113.5 back, and wrote the annotation. Everything after by describes the receiving server itself.

The annotation is attached to the PTR name, and it sits on the hop where your sending IP met that particular receiver. It says nothing about the From address or about who wrote the message.

Compare the same hop on a message whose sending IP has a correct PTR:

Received: from mail.yourdomain.example (mail.yourdomain.example [203.0.113.5])
        by mx.receiver.example (8.17.1/8.17.1) with ESMTPS id 486Bq2Xp012346

Same HELO name, same IP, no annotation, because the PTR for 203.0.113.5 returned mail.yourdomain.example and the A record for that name returned 203.0.113.5. Forward and reverse agree. That agreement has a name, forward-confirmed reverse DNS, and it’s the whole of what the annotation tests.

What the annotation doesn’t test

Spoofing, in the sense people mean when they type “may be forged” into a search box, is somebody sending mail with your domain in the From address. The mechanisms that catch that are SPF, DKIM and DMARC, and their verdicts appear in a different header entirely:

Authentication-Results: mx.receiver.example;
        spf=pass smtp.mailfrom=yourdomain.example;
        dkim=pass header.d=yourdomain.example header.s=s1;
        dmarc=pass header.from=yourdomain.example

A single message can carry “(may be forged)” in its Received line and dmarc=pass two lines below it, and that combination is ordinary. The reverse DNS check ran against the IP at connection time, while the authentication checks ran against the envelope sender, the signature and the From header, so one result has no bearing on the other. A message can also fail SPF and DMARC outright while its Received line is clean, because the sending IP had a tidy PTR and no business sending for your domain.

Advice to add a DMARC record to fix “may be forged” confuses the two. A record in your domain’s zone changes nothing about the PTR for an IP address, so you’ll add it and the annotation will still be there the next time you look. If you’re worried about somebody impersonating the domain, that’s a fair question, and can someone spoof my domain answers it from the DMARC and SPF records, which are the ones that decide it.

The warnings you can see in a mail client aren’t driven by the annotation either. The banner some clients show saying a sender failed fraud detection checks, or the question mark others put beside an unauthenticated sender, come from the authentication results. If your own mail is being flagged to your own colleagues, read the Authentication-Results header first, because that’s where the client formed its opinion. Email delivery walks through reading that header when mail lands in spam.

Whose record it is

PTR records don’t live in your domain’s zone. The reverse tree is in-addr.arpa for IPv4 and ip6.arpa for IPv6, and the part of it covering your address is delegated to whoever holds the address block, usually the hosting company or the ISP. You can hold every record for yourdomain.example and still have no power over what 5.113.0.203.in-addr.arpa says.

That’s why this ends up on your desk rather than with your DNS host. The sending IP tends to be a box somebody set up years ago: an on-premises server, a VPS running the CRM, a web host firing form submissions straight out over port 25, a multifunction printer scanning to email. The provider gave the address a generic PTR at allocation time and nobody has touched it since. The forward record for that generic name either doesn’t exist or points somewhere else, so the confirmation fails.

The census sees the same neglect from the receiving side. Of the 173,216,907 domains where the reverse DNS check ran in the September 2026 census, 134,848,964 (77.8%) had a mail host with a PTR record and 38,367,943 (22.2%) had none. That check looks at the host a domain publishes for inbound mail, and for a small organisation running its own server that’s the same machine doing the sending.

Checking it yourself

You need the sending IP, and you have it: it’s the bracketed address on the annotated line. Look it up backwards, then look the result up forwards.

$ dig -x 203.0.113.5 +short
host-5-113-0-203.static.isp.example.

$ dig A host-5-113-0-203.static.isp.example +short
198.51.100.77

The forward answer came back with a different address, so any sendmail receiver will annotate the hop and any Postfix receiver will log it. On Windows, nslookup 203.0.113.5 followed by nslookup on the name it returns gives the same pair of answers. If the first command returns nothing, you’re in the no-PTR case, which shows up as a bare [203.0.113.5] in sendmail’s header and as unknown in Postfix’s.

Postfix is worth knowing about because plenty of the servers you send to run it, and it doesn’t use the phrase. Its Received header for the same mismatch reads:

Received: from mail.yourdomain.example (unknown [203.0.113.5])

and its log carries the reason:

warning: hostname host-5-113-0-203.static.isp.example does not resolve to address 203.0.113.5

Where it starts to cost you is a receiver that has turned the check into a policy. A Postfix administrator can set reject_unknown_reverse_client_hostname, which refuses any IP with no PTR, or reject_unknown_client_hostname, which also refuses the mismatch case. Your server then sees this on its outbound attempt:

450 4.7.25 Client host rejected: cannot find your reverse hostname, [203.0.113.5]

That’s a temporary failure, so your queue retries for days and then bounces, and the bounce is what usually starts the ticket that ends with you reading headers.

The fix, and who has to make it

Decide what name the sending machine should have. It should be a name in a zone you control, it should be the name the server uses in its HELO, and it needs an A record (and an AAAA record if the server connects over IPv6) pointing at the sending address. mail.yourdomain.example does fine.

Then get the PTR changed. On most cloud and hosting providers this is a field in the console labelled reverse DNS, rDNS or PTR, set per IP address, and the change shows up within minutes. On a business ISP line it’s a support request, and the ISP may want to see the forward record in place before they set it. A few providers will delegate the reverse zone for a whole block to your nameservers, which is more than you need for one mail server.

Set the HELO name on the server to match. In Postfix that’s myhostname = mail.yourdomain.example in main.cf; in sendmail it’s the $j macro, normally derived from the host’s own name. On a printer or an appliance it’s a field called hostname or device name somewhere in the network settings, and leaving it at the factory default is how a printer’s model number ends up as the HELO name in somebody’s Received header.

Then repeat the two lookups. When dig -x returns your name and dig A on that name returns your IP, send a message to a mailbox where you can read the headers and confirm the annotation has gone. It will have gone for every receiver at once, because you changed the one record they all consult.

When it’s on someone else’s mail

If the annotated line is on a message you received from a supplier or a customer, the IP and the PTR are theirs, and there’s nothing on your side to change. Send them the Received line and the two dig commands above; their hosting provider will set the PTR once someone asks. Don’t treat the message as suspect on the strength of the annotation alone. Read the Authentication-Results header, and if DMARC passed for their domain, the message came from where it claims.

If the line is on a message that claims to be from your domain and you didn’t send it, look past the annotation. What decides whether the receiver should have accepted it is your DMARC policy and whether the message failed alignment against it; the word forged in that header only ever described a lookup result.

Run the free scan on your domain and it will read the PTR for your published mail host back to you alongside your DMARC and SPF records and the rest of your DNS, so you can see in one place which record is the one that’s missing.

Figures as of 5 September 2026, from the September 2026 edition of the defaults.exposed census. Census numbers move every month; the current values are on the census data page.