Understanding MX Records and How Email Routing Actually Works
Every email you send survives a small odyssey through DNS lookups, priority values, and a chain of mail servers before it lands. Here is the full journey, the misconfigurations that break it, and how to inspect any domain's mail setup with dig.
EvilMail TeamMay 22, 202613 min read
# Understanding MX Records and How Email Routing Actually Works
Type an address, write a few sentences, hit send. Somewhere between that click and the message appearing in someone's inbox, a surprising amount of infrastructure quietly does its job — and almost all of it hinges on a single, unglamorous line of DNS called an MX record. Most people never think about it until the day mail stops flowing and someone asks, with rising panic, "why are our emails bouncing?" The answer is nearly always in the MX records, and once you understand how they work you can diagnose in minutes what otherwise looks like black magic.
This is a tour of that machinery. We will start with what an MX record actually is, follow a message from the sender's keyboard all the way to the recipient's mailbox, look at how priority and fallback really behave, catch the misconfigurations that bite people most often, and finish with the exact commands you use to inspect any domain's mail setup yourself. No hand-waving — real records, real dig output, real failure modes.
What an MX record actually is
MX stands for Mail Exchanger. It is a type of DNS record whose entire job is to answer one question: "If I want to deliver mail to addresses at this domain, which server or servers should I hand it to?" That is it. An MX record does not carry mail, does not store mail, and does not know anything about mailboxes. It is a signpost.
The critical distinction that trips up beginners: the domain in an email address and the server that receives its mail are two different things, and MX records are the mapping between them. When you email
part is not necessarily a mail server at all — it is a domain whose MX records point at wherever mail should go, which might be Google, Microsoft, a self-hosted box, or a filtering service that forwards onward.
An MX record has two components that matter:
A preference value (also called priority) — an unsigned integer, lower means more preferred.
A mail exchanger hostname — the name of the server to deliver to, which must itself resolve to an A or AAAA record (an IP address).
A minimal set for a domain using Google Workspace looks like this:
example.com. 3600 IN MX 1 aspmx.l.google.com.
example.com. 3600 IN MX 5 alt1.aspmx.l.google.com.
example.com. 3600 IN MX 5 alt2.aspmx.l.google.com.
example.com. 3600 IN MX 10 alt3.aspmx.l.google.com.
example.com. 3600 IN MX 10 alt4.aspmx.l.google.com.
Reading left to right: the domain, the TTL (how long a resolver may cache this, in seconds), the class (IN for internet, effectively always), the type (MX), the preference value, and the target hostname. The trailing dots are not typos — they mark a fully qualified name, and forgetting them in a zone file is a classic self-inflicted wound we will come back to.
One rule about the mail exchanger hostname
The hostname an MX record points to has a rule that people break constantly: it must be a hostname with an address record, never an IP address and never a CNAME.
This is not a stylistic preference; it is in the specification, and it has real consequences. An MX record like MX 10 192.0.2.25 is invalid — you must point to something like mail.example.com and then give mail.example.com its own A record pointing to 192.0.2.25. Pointing an MX at a CNAME (an alias) is likewise forbidden and, depending on the sending server, will either work by luck or fail silently in ways that are miserable to debug. When you set up mail, the target of every MX record should be a plain hostname with a direct A/AAAA record. Memorize that and you avoid a whole category of pain.
Priority and preference: lower wins
The preference value is the most misunderstood number in email. Here is the mental model that makes it click: lower is more important. A server with preference 1 is tried before a server with preference 10. Think of it as a ranked list of "try these in order," not as a percentage or a weight.
Consider this set:
| Preference | Mail exchanger | Role | |---|---|---| | 10 | mx1.example.com | Primary — gets all mail normally | | 20 | mx2.example.com | Secondary — used only if primary is down | | 30 | mx-backup.thirdparty.net | Last resort — a backup MX elsewhere |
Under normal conditions, every message goes to mx1 because 10 is the lowest number available. If mx1 is unreachable — the server is down, the connection times out, the port is closed — the sending server falls back to mx2 at preference 20. Only if both of those fail does it reach for the backup at 30.
Two details people get wrong:
The actual numbers do not matter, only their relative order. Values of 10/20/30 behave identically to 1/2/3 or 5/50/500. There is nothing special about multiples of ten; it is a convention that leaves room to insert records later.
Equal preferences mean load balancing. When two or more MX records share the same preference value — as in the Google example earlier, where several sit at 5 — the sending server picks among them at random (ideally weighted by nothing, just chance). This spreads load across multiple front-end servers. So equal numbers mean "these are interchangeable, pick one," while different numbers mean "try them in order."
1. Submission. Alice's mail client connects to her own outgoing server — her MSA, or Mail Submission Agent, usually on port 587 with authentication. She proves who she is, hands over the message, and her part is done. Her client does not talk to Bob's server directly; that is a common misconception. Outbound mail goes through her provider first.
2. The sending MTA takes over. Company.com's Mail Transfer Agent now owns the message and must figure out where example.com accepts mail. It does not guess. It asks DNS.
3. The MX lookup. The sending MTA performs a DNS query for the MX records of example.com. The resolver returns the list of mail exchangers with their preference values. Say it gets back mx1.example.com at 10 and mx2.example.com at 20.
4. Resolving the exchanger to an IP. MX records give hostnames, not addresses. So the MTA does a second lookup — an A (IPv4) or AAAA (IPv6) query — on mx1.example.com to get an actual IP like 203.0.113.25. This is the two-step nobody sees: MX to get the name, A/AAAA to get the address.
5. The SMTP conversation. The sending MTA opens a TCP connection to that IP on port 25 — the port reserved for server-to-server mail transfer. The two servers speak SMTP: a greeting (HELO/EHLO), who the message is from (MAIL FROM), who it is for (RCPT TO), and then the message body after DATA. If the receiving server accepts, it says so with a 250 response code, and responsibility for the message transfers.
6. Authentication checks on arrival. Before or during acceptance, the receiving MTA typically runs the sender through SPF (is this IP allowed to send for company.com?), DKIM (is the cryptographic signature valid?), and DMARC (does the domain's policy say to trust or reject this?). Fail these badly and the message is rejected or quarantined here, MX records notwithstanding. Routing and authentication are separate layers that people often conflate.
7. Local delivery. The receiving MTA now has the message and hands it to a Mail Delivery Agent, which files it into Bob's actual mailbox on disk — applying filters, spam scoring, and folder rules along the way.
8. Bob reads it. Later, Bob's mail client fetches the message over IMAP (or POP3) and displays it. That retrieval has nothing to do with MX records; MX governed only the delivery half of the trip.
The whole sequence, when everything is healthy, takes well under a second. When it does not, every one of these steps is a place it can break — and knowing the steps is how you find which one.
Fallback, retries, and what "the mail is delayed" really means
Mail is designed to be stubborn. Unlike a web request that fails and shows an error, a mail server that cannot deliver does not give up on the first try.
If every MX host for a domain is unreachable — all of them, at every preference level — the sending server does not bounce the message immediately. It queues it and retries on a schedule, typically with increasing gaps: a few minutes, then longer, then hourly, over a window that is usually several days. During this time the sender may receive a "delayed" notification, which means "still trying, not dead yet." Only after the retry window fully expires does the server generate a bounce — a non-delivery report explaining the failure.
This is why a brief mail-server outage often causes no lost mail at all: messages pile up in senders' queues and flush through once your server answers again. It is also why "we didn't get your email" is worth investigating rather than assuming permanent loss; the message may still be circling in someone's retry queue.
The backup MX at a higher preference number exists for exactly this scenario, but it is a double-edged tool. A backup MX that just queues mail and forwards it to your primary later can help ride out outages — but if it is not configured to know your valid recipients, it happily accepts mail for addresses that do not exist and becomes a magnet for spam and backscatter. Many modern setups skip the backup MX entirely and rely on sender-side retry queues, which are more reliable than a poorly maintained secondary.
The misconfigurations that actually bite
After enough time staring at broken mail, the same handful of mistakes recur. In rough order of frequency:
No MX record at all. With no MX, well-behaved senders fall back to the domain's A record as an implicit mail exchanger. Sometimes that accidentally works; usually the A record points at a web server that has no idea what to do with SMTP, and mail bounces. If you want mail, publish explicit MX records.
MX pointing at a CNAME. As covered above, this violates the spec. It may work with lenient senders and fail with strict ones, producing the maddening "some people can email us and some can't" bug.
The mail exchanger hostname has no A/AAAA record. The MX resolves to a name, the name resolves to nothing, delivery fails at step 4. Often caused by a typo in the target hostname.
Missing trailing dot in a zone file. Writing mail.example.com without the final dot in a BIND-style zone makes the server helpfully append the origin, yielding mail.example.com.example.com. Instant breakage, and easy to miss because it looks right at a glance.
Stale records after a migration. You move from one provider to another but old MX records linger, or the change has not propagated because of a long TTL. Mail keeps flowing to the old server for hours. Lower your TTL before a planned migration so changes take effect quickly.
Firewall blocking port 25. The DNS is perfect but the receiving server never answers on 25 because a firewall or ISP blocks it. The MX lookup succeeds; the SMTP connection times out. This one fools people because the records look flawless.
Only IPv6, or broken IPv6. If your MX host has an AAAA record that points somewhere unreachable, IPv6-preferring senders fail while IPv4 senders succeed — another "only some people" ghost.
The pattern worth internalizing: intermittent, sender-dependent delivery failures usually come from something being spec-legal-ish but not quite right — a CNAME, a broken fallback, an IPv6 record — because strict senders reject what lenient ones tolerate.
Inspecting mail setup with dig and nslookup
You do not have to take anyone's word for a domain's mail configuration. You can read it directly. The tool of choice on Linux and macOS is dig.
The +short flag strips everything but the answer. Drop it for the full picture, including which server answered and the TTL:
$ dig MX gmail.com
;; ANSWER SECTION:
gmail.com. 3600 IN MX 5 gmail-smtp-in.l.google.com.
gmail.com. 3600 IN MX 10 alt1.gmail-smtp-in.l.google.com.
gmail.com. 3600 IN MX 20 alt2.gmail-smtp-in.l.google.com.
gmail.com. 3600 IN MX 30 alt3.gmail-smtp-in.l.google.com.
gmail.com. 3600 IN MX 40 alt4.gmail-smtp-in.l.google.com.
Note the clean priority ladder: 5, 10, 20, 30, 40. One preferred front-end, then a descending chain of alternates.
Always finish the job by confirming the exchanger actually resolves to an address — the step that catches broken targets:
$ dig A mx1.example.com +short
203.0.113.25
If that comes back empty, you have found your problem: the MX points at a name that does not exist.
To bypass caching and ask a specific public resolver — useful for checking whether a recent change has propagated — aim dig at one directly:
$ dig MX example.com @8.8.8.8 +short
Comparing the answer from your own resolver against a fresh one like 8.8.8.8 is the fastest way to tell whether a change has gone live or is still hiding behind a cached TTL.
On Windows, or if dig is unavailable, nslookup does the same in a clunkier dialect:
A sensible verification routine when you set up or troubleshoot a domain: query the MX records, confirm the preferences are in the order you intended, resolve each exchanger hostname to make sure it has a live A/AAAA record, and — if you can — test that something actually answers SMTP on port 25 at that address. If you run disposable or throwaway inboxes the way a service like EvilMail does, this same MX plumbing is exactly what makes an address reachable the instant it is created; the records are the difference between a domain that receives mail and one that just looks like it should.
MX records are a small idea doing enormous work: a signpost in DNS that turns the right-hand side of an email address into a real server on the real internet. Once you can read them, follow the journey they govern, and reach for dig when something breaks, email stops being magic and becomes what it actually is — a chain of well-defined steps, each of which you can inspect, and any one of which you can now fix.