Safeguard
Supply Chain Security•

Self-Hosted Mail Server: MTA, IMAP, SPF, DKIM, DMARC and MTA-STS

A self-hosted mail server is an SMTP MTA, IMAP server, filter and DNS records. Publish SPF, DKIM, DMARC and MTA-STS; relay if your IP is residential.

Safeguard Security Team
46 min read

A self-hosted mail server is programs you run yourself: an SMTP transfer agent that sends and receives, a delivery agent, an IMAP server your devices read from, and a filter. It delivers well only when DNS proves who you are, so publish MX, PTR, SPF, DKIM, DMARC and MTA-STS, and relay outbound mail from residential IPs.

This guide goes one level deeper than our post on replacing Gmail with private email on a custom domain, which covers choosing a provider and moving your mail safely, and it pairs with our defender's history of SMTP abuse from open relays to SMTP smuggling. If the server will sit on your home network, read the guide to building a home firewall on a mini PC first. Protocol details come from the RFCs, provider requirements from each provider's own pages, and settings from the Postfix, Dovecot and Rspamd documentation, all checked on 24 October 2026.

Key takeaways

  • A mail server is several cooperating parts. The mail transfer agent (MTA) speaks SMTP (RFC 5321) to other servers, a submission service accepts mail from your own authenticated users on port 587 or 465, a delivery agent writes mail into mailboxes, and an IMAP server lets clients read it. Spam filtering and DKIM signing usually sit beside the MTA as a milter.
  • Six DNS records do most of the work. MX says where to deliver, PTR ties your IP back to a hostname, SPF (RFC 7208) lists the IPs allowed to send for a domain, DKIM (RFC 6376) publishes a public key that verifies a signature, DMARC ties SPF and DKIM results to the visible From address, and MTA-STS (RFC 8461) tells other servers to require TLS when delivering to you.
  • DMARC changed in May 2026. RFC 7489 (March 2015, Informational) is now obsoleted by RFC 9989, 9990 and 9991, all Proposed Standards. The pct, rf and ri tags are gone; np, psd and t are new; and a DNS tree walk replaces the public suffix list for finding the organizational domain.
  • Receiving mail at home is the easy half. Sending is hard because many networks block outbound port 25, residential address ranges carry poor reputation, and you often cannot set reverse DNS. A relay or smarthost on port 587 is the common, legitimate answer.
  • Gmail, Yahoo and Outlook.com publish sender requirements. All three expect authentication, valid forward and reverse DNS and low complaint rates. For high volume senders, all three require SPF, DKIM and a DMARC policy of at least p=none with alignment, plus one-click unsubscribe for marketing mail at Gmail and Yahoo.
  • Security is mostly configuration (TLS, authentication only over TLS, no open relay, rate limits) plus fast patching. Back up mailboxes and DKIM keys, read DMARC reports and watch the queue.

What are the parts of a mail server?

A "mail server" is really four or five programs, each with a narrow job, connected by local sockets or SMTP-like protocols. Knowing which part does what tells you where TLS goes and which log to read when something breaks.

The mail transfer agent (MTA)

The MTA is the part that speaks SMTP to the rest of the internet. RFC 5321, published in October 2008 and obsoleting RFC 2821, is the current definition of SMTP. It describes a client and a server: the client opens a TCP connection, the server greets it, and the client sends a sequence of commands (EHLO, MAIL FROM, RCPT TO, DATA) followed by the message. The server answers each command with a three digit reply code. Codes starting with 2 mean success, 4 means try again later, and 5 means a permanent failure.

Your MTA plays both roles: a server on port 25 for mail to your domains, and a client that looks up each recipient domain's MX and delivers outbound mail. Postfix splits these into processes: smtpd (server), smtp (client), qmgr (queue) and optionally postscreen in front of smtpd.

RFC 5321 separates the envelope (MAIL FROM and RCPT TO) from the message (headers and body after DATA, defined by RFC 5322). They can differ: a mailing list's envelope sender is its bounce address while From: names the author. That split is why SPF, DKIM and DMARC all exist.

The submission service (MSA)

Your own users should not send mail through port 25. RFC 6409 (November 2011) defines message submission on port 587, where clients authenticate before they send, and RFC 8314 (January 2018) adds implicit TLS submission on port 465 and states a preference for implicit TLS over STARTTLS for submission and mail access. In Postfix, both are additional smtpd instances defined in master.cf with stricter settings: TLS required, SASL authentication required, and relaying only for authenticated clients.

The separation matters. Port 25 must accept unauthenticated connections from any server on the internet, because that is how mail reaches you. Ports 587 and 465 must accept nothing from anyone who has not logged in.

The delivery agent and LMTP

The delivery agent writes accepted mail to disk. Postfix ships local and virtual agents, but a common design hands final delivery to the IMAP server over LMTP (Local Mail Transfer Protocol). Postfix documents a mailbox_transport parameter for exactly this: the local delivery agent passes mailbox delivery to the named transport, such as lmtp:unix:private/dovecot-lmtp. Letting Dovecot deliver means its indexes stay current and server-side filters (Sieve) run at delivery time.

The IMAP server

The IMAP server stores mailboxes and lets clients read, search, move and flag messages without downloading everything. Dovecot is the most common open source choice; its community edition documentation currently covers 2.4.5 and the older 2.3 branch. Dovecot also often provides the SASL authentication backend that Postfix uses for the submission ports, so a user's IMAP password and SMTP password are the same credential checked in one place.

Maildir stores one file per message, which makes backups and partial restores simple; Dovecot's own sdbox and mdbox formats are faster at scale but need Dovecot tools to read. The Dovecot 2.4 quick configuration uses sdbox; the walkthrough below uses Maildir because it is easier to inspect on a small server.

Filtering, DKIM signing and webmail

Between the MTA receiving a message and the delivery agent filing it, most servers run a content filter. The usual integration point is a milter, a protocol Postfix supports through smtpd_milters. A single filtering daemon can score inbound mail for spam, check SPF, DKIM and DMARC on inbound mail, and add a DKIM signature to outbound mail. Rspamd, used below, documents a dkim_signing module that signs authenticated users' mail by default.

Webmail is optional: a web application that speaks IMAP and submission for the user, and often the most exposed part of the stack. Skip it if you do not need it.

How a message travels between them

Here is a single message from alice@example.com (your server) to bob@example.net (somewhere else), and the reply.

  1. Alice's mail client connects to mail.example.com on port 587, upgrades to TLS with STARTTLS (or connects on 465 with implicit TLS), and authenticates. Postfix asks Dovecot over a local socket whether the password is valid.
  2. The submission smtpd accepts the message because the client is authenticated. The milter adds a DKIM signature for example.com. The message enters the queue.
  3. The Postfix SMTP client looks up the MX record for example.net, connects to the named host on port 25, issues EHLO, upgrades to TLS if offered, and sends MAIL FROM:<alice@example.com>, RCPT TO:<bob@example.net> and the message.
  4. The receiving server checks the connecting IP's reverse DNS, evaluates SPF for the envelope domain, verifies the DKIM signature, looks up the DMARC policy for the From: domain, and decides whether to accept, file as spam, or reject.
  5. When Bob replies, the same process runs in reverse. A server at example.net looks up your MX, connects to your port 25 (checking MTA-STS first if it supports it), and hands the message to your smtpd. Postfix passes it through the milter for spam scoring and authentication checks, then to Dovecot over LMTP, which writes it into Alice's Maildir.
  6. Alice's client sees the new message through IMAP on port 993.
PartProtocol and portJobExample software
MTA, inboundSMTP, TCP 25Accept mail for your domains from other serversPostfix smtpd (optionally behind postscreen)
MTA, outboundSMTP, TCP 25 (or 587 to a relay)Deliver your users' mail to other domainsPostfix smtp client
Submission (MSA)SMTP with AUTH, TCP 587 (STARTTLS) and 465 (implicit TLS)Accept mail from your own logged-in usersPostfix smtpd instances in master.cf
Delivery agentLMTP over a Unix socketWrite accepted mail into mailboxesDovecot LMTP
Mail accessIMAP, TCP 993 (implicit TLS)Let clients read and manage mailDovecot IMAP
Filter and signerMilterSpam scoring, inbound auth checks, outbound DKIM signingRspamd
Webmail (optional)HTTPSBrowser access through IMAP and submissionAny IMAP webmail application

Which DNS records does a mail server need, and what does each prove?

Each record answers a different question for a receiver; the table at the end of this section summarises them.

MX: where to deliver

An MX record lists the hostnames that accept mail for a domain, each with a preference number; lower numbers are tried first. RFC 5321 describes the lookup: a sending server queries MX for the recipient domain, sorts the results, and tries each host in turn. If there is no MX at all, RFC 5321 falls back to the domain's address record, an implicit MX.

If a domain should never receive mail, RFC 7505 (June 2015) defines a "null MX": a single MX record with preference 0 and a target of . Senders that understand it stop trying immediately instead of queuing. It is worth publishing on parked and web-only domains, alongside an SPF record of v=spf1 -all and a DMARC reject policy, so nobody can credibly send as them.

A, AAAA and PTR: forward and reverse DNS

The MX target needs A (and, if you use IPv6, AAAA) records. Outbound mail needs the reverse: a PTR record on the sending IP that resolves to a hostname, and that hostname must resolve back to the same IP. This forward and reverse match is a hard requirement at Gmail for all senders: Google says the sending IP "must match the IP address of the hostname specified in the Pointer (PTR) record." Yahoo asks for "valid, meaningful, non-generic" reverse DNS that reflects your domain, and warns against names that look like dynamically assigned addresses.

You do not control PTR records through your domain's DNS. They live in the reverse zone of whoever owns the IP block, usually your ISP or hosting provider. That one fact decides a lot of self-hosting plans, as the section on residential IPs explains.

Your PTR, your myhostname setting in Postfix and the name in your TLS certificate should all be the same name, for example mail.example.com. The SMTP greeting and EHLO name then match what receivers find in DNS.

SPF: which IPs may use this envelope domain

SPF is defined by RFC 7208 (April 2014, obsoleting RFC 4408). A domain publishes a TXT record starting with v=spf1, followed by mechanisms that describe authorized senders and a final default. A receiver evaluates it against the connecting IP and the domain in the envelope MAIL FROM (and the HELO name).

example.com. IN TXT  "v=spf1 mx -all"

That record says: the hosts named in this domain's MX records may send, and everything else fails. If you relay through a provider, add their published include: mechanism.

Two limits from RFC 7208 catch people out. Mechanisms that cause DNS lookups (include, a, mx, ptr, exists and the redirect modifier) count toward a limit of 10 per evaluation; exceeding it produces a permanent error, which most receivers treat as a failure. And RFC 7208 says implementations should limit "void lookups" (queries that return no records) to two. Microsoft's Outlook.com guidance repeats the first point: "If you exceed 10 DNS lookups, your SPF check might fail."

What SPF proves: that the IP was authorized by the envelope domain. What it does not prove: anything about the From: header a person sees, or anything after a message is forwarded, because the forwarder's IP is not in your record.

DKIM: a signature that survives forwarding

DKIM, defined in RFC 6376 (September 2011, now an Internet Standard), lets a signing domain attach a cryptographic signature to selected headers and the body. The signature header names the signing domain (d=) and a selector (s=), and the receiver fetches the public key from a TXT record at selector._domainkey.domain.

dkim._domainkey.example.com. IN TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqh...IDAQAB"

RFC 8301 (January 2018) updated DKIM's crypto rules: signers must not use rsa-sha1, must use RSA keys of at least 1024 bits and should use at least 2048 bits. RFC 8463 later added an Ed25519 signing method, but because not every verifier supports it, signers that use Ed25519 usually add an RSA signature too.

What DKIM proves: that the signing domain took responsibility for the message and that the signed parts have not changed. A DKIM signature usually survives plain forwarding because it does not depend on the sending IP. It can break when a mailing list rewrites the subject or adds a footer.

DMARC: tying it to the visible From address

DMARC answers the question SPF and DKIM leave open: does an authenticated domain match the domain the reader sees? A domain publishes a policy at _dmarc.domain. A message passes DMARC when SPF or DKIM passes for a domain that is aligned with the From: header domain. Relaxed alignment (the default) accepts the same organizational domain; strict alignment needs an exact match.

_dmarc.example.com. IN TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"

The policy (p=) asks receivers to do nothing special (none), treat failures as suspicious (quarantine), or refuse them (reject). rua= asks receivers to send daily aggregate reports.

The standard changed this year. RFC 7489 (March 2015) was an Informational document from the Independent Submission stream. In May 2026 it was replaced by three Proposed Standards: RFC 9989 (core protocol), RFC 9990 (aggregate reporting) and RFC 9991 (failure reporting). The changes that matter to a self-hoster:

  • The pct tag, which applied a policy to only a percentage of mail, is removed. A new t tag (test mode, t=y) replaces some of what it did by asking receivers not to apply the policy while you test.
  • The rf (failure report format) and ri (report interval) tags are removed.
  • np (policy for non-existent subdomains, imported from RFC 9091) and psd (a flag for public suffix domains) are added.
  • Receivers find the organizational domain with a "DNS tree walk" up the name rather than by consulting a public suffix list.

Records written for RFC 7489 still parse: unknown tags are ignored, and p, sp, rua, adkim and aspf work as before. If your record contains pct=, plan to remove it.

What DMARC proves: that the visible sender's domain owner authenticated the message, through SPF or DKIM. What it does not prove: that the content is safe, or that a lookalike domain is not impersonating you.

MTA-STS: require TLS when others deliver to you

Server-to-server STARTTLS is opportunistic, so an attacker on the path can strip the offer and force plaintext. MTA-STS, defined in RFC 8461 (September 2018), lets a domain declare that senders must use TLS with a valid certificate when delivering to its MX hosts.

It has two parts. A TXT record at _mta-sts.example.com signals that a policy exists and carries an id that you change whenever the policy changes. The policy itself is a small text file served over HTTPS at https://mta-sts.example.com/.well-known/mta-sts.txt:

version: STSv1
mode: enforce
mx: mail.example.com
max_age: 604800

mode is enforce, testing or none. max_age is how long senders may cache the policy, in seconds, with a maximum of 31,557,600 (about one year). Each MX host gets its own mx: line, and wildcards like *.example.net are allowed.

MTA-STS protects mail coming to you. Whether your own outbound mail honours other domains' policies depends on your MTA. Postfix's documentation refers to "an STS policy plugin" connected through smtp_tls_policy_maps; the Postfix SMTP client does not fetch MTA-STS policies by itself.

TLS-RPT: find out when TLS fails

RFC 8460 (September 2018) defines SMTP TLS Reporting. You publish a TXT record at _smtp._tls.example.com such as v=TLSRPTv1; rua=mailto:tlsrpt@example.com, and senders that support it send you JSON reports, each normally covering a full UTC day, of successful and failed TLS sessions to your MX hosts. It is the feedback loop that makes switching MTA-STS from testing to enforce safe.

Record summary

RecordNameDefined inWhat it provesWhat it does not prove
MXexample.comRFC 5321Which hosts accept mail for the domainAnything about senders
Null MXexample.comRFC 7505The domain accepts no mailAnything about senders
A or AAAAmail.example.comDNSThe MX host's addressIdentity
PTRReverse zone of your IPDNSThe IP's owner named it, and the name maps backDomain authorization
SPFexample.com TXTRFC 7208The IP may send for the envelope domainAnything about the From: header; survives no forwarding
DKIMselector._domainkey.example.com TXTRFC 6376, RFC 8301The signing domain vouched for unchanged signed contentThat d= matches the From: domain
DMARC_dmarc.example.com TXTRFC 9989 (formerly RFC 7489)SPF or DKIM passed for a domain aligned with From:That content is benign; lookalike domains
MTA-STS_mta-sts.example.com TXT plus HTTPS policyRFC 8461Senders must use valid TLS to your MXEncryption at rest or end to end
TLS-RPT_smtp._tls.example.com TXTRFC 8460Nothing; it requests reportsNothing

Why is sending mail from a home IP address so hard?

Receiving at home is usually fine. Sending, and landing in inboxes, is where the time goes, for three reasons.

Outbound port 25 is often blocked

Many networks block outbound connections to port 25 from ordinary customer addresses, because compromised home computers have long been a source of spam. Cloud providers do the same. Google Cloud's documentation is explicit: "Due to the risk of abuse, connections to destination TCP Port 25 are blocked when the destination is external to your VPC network," and it directs users to send through a relay on ports 587, 465 or 2525. Check your own ISP's or provider's terms; if port 25 is blocked, no server configuration will fix it.

Reputation follows the address block

Receivers judge an IP partly by its history and by its neighbourhood. Address ranges assigned dynamically to home connections are widely treated as places mail servers should not be. A fresh static IP has no history at all, which is not the same as a good history.

You probably cannot set reverse DNS

As explained above, Gmail requires forward and reverse DNS for all senders, and Yahoo asks for a PTR that reflects your domain and does not look dynamic. On most residential connections the PTR is fixed by the ISP to a generic name, and you cannot change it. Some business plans and most virtual private server providers let you set it.

When a relay or smarthost makes sense

A relay (also called a smarthost) is an outbound SMTP service you authenticate to on port 587 or 465. Your server hands it all outbound mail, and the relay delivers it from its own IPs, which have established reputation and correct reverse DNS. Inbound mail still comes straight to your server on port 25.

A relay makes sense when outbound port 25 is blocked, you cannot set a PTR, your IP is residential, or you send too little mail to build reputation yourself.

With a relay, add the relay's SPF include: to your record, keep signing with your own DKIM key so DMARC aligns on DKIM regardless of the relay's envelope domain, and check the relay's terms on volume and content. The cost is that a third party now sees your outbound mail in transit. That is a privacy trade you should make knowingly.

What do large mailbox providers require from senders?

Gmail, Yahoo and Outlook.com publish sender requirements that apply to everyone sending to their users. The summary below comes from each provider's own pages; they change, so check before relying on a figure.

Gmail

Google's "Email sender guidelines" set requirements for anyone sending to personal Gmail accounts (addresses ending in @gmail.com or @googlemail.com) starting 1 February 2024. All senders must set up SPF or DKIM, have valid forward and reverse DNS, use a TLS connection, keep spam rates reported in Postmaster Tools below 0.3%, and format messages according to RFC 5322. Senders of 5,000 or more messages a day to Gmail accounts must also set up both SPF and DKIM, publish a DMARC policy (which "can be set to none"), align the From: domain with the SPF or DKIM domain, and support one-click unsubscribe for marketing and subscribed messages, with a visible unsubscribe link in the body. One-click unsubscribe means the List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers defined in RFC 8058.

Yahoo

Yahoo's sender best practices page says enforcement of its standards began in February 2024 and rolled out gradually through the first half of that year. All senders must implement SPF or DKIM, keep the spam rate below 0.3% and have valid forward and reverse DNS. Bulk senders must implement both SPF and DKIM, publish a DMARC policy of at least p=none that passes, align the From: domain, support one-click unsubscribe and honour unsubscribes within 2 days. Yahoo's FAQ says it "will not specify a volume threshold" for who counts as a bulk sender, and that spoofed mail sent in your domain's name counts toward the volume it looks at.

Outlook.com

Microsoft announced requirements for Outlook.com, its consumer service covering hotmail.com, live.com and outlook.com addresses, in a post dated 2 April 2025 and updated on 30 April 2025. Domains sending more than 5,000 messages a day must pass SPF and DKIM and publish DMARC of at least p=none, aligned with SPF or DKIM, "preferably both." On enforcement, the updated post says non-compliant messages from 5 May 2025 receive a rejection, "550; 5.7.515 Access denied", while an earlier paragraph still in the same post describes routing to Junk first, with rejection at a later date. Read the current version yourself. The same post says Outlook.com sends DMARC aggregate reports but has no plans to send failure reports, and that adding a sender to a recipient's safe senders list does not bypass enforcement.

What the three agree on

RequirementGmail (all senders)Gmail (5,000+ a day)Yahoo (all)Yahoo (bulk)Outlook.com (5,000+ a day)
SPF or DKIMRequiredBoth requiredRequiredBoth requiredBoth required
DMARCRecommendedAt least p=noneStrongly urgedAt least p=none, must passAt least p=none
From alignmentNot statedRequiredNot statedRequiredRequired (SPF or DKIM)
Forward and reverse DNSRequiredRequiredRequiredRequiredNot listed in the post
TLSRequiredRequiredNot listedNot listedNot listed
Complaint rateUnder 0.3%Under 0.3%Under 0.3%Under 0.3%Not stated as a number
One-click unsubscribeNot requiredRequired for marketingNot requiredRequired for marketingFunctional unsubscribe link
Effective1 Feb 20241 Feb 2024Feb 2024Feb 20245 May 2025

A personal server is not a bulk sender, but meeting the bulk bar costs nothing. Treat these as a floor; none promises inbox placement.

How do you secure a self-hosted mail server?

A mail server accepts data from strangers and holds private correspondence. Securing it is mostly a few settings plus current software.

TLS on every hop you control

  • Inbound on port 25: offer STARTTLS with smtpd_tls_security_level = may. Postfix's TLS documentation notes that RFC 2487 forbids requiring TLS on a publicly referenced server, because some legitimate senders still cannot do it; MTA-STS is how you ask capable senders to insist on it.
  • Outbound: use opportunistic TLS (smtp_tls_security_level = may). In Postfix 3.11 and later this is the default; earlier releases default to empty, so set it explicitly. When you relay through a smarthost, use encrypt or secure for that one destination.
  • Submission and IMAP: require TLS. Postfix's smtpd_tls_auth_only = yes refuses AUTH until TLS is active, and Dovecot's ssl = required refuses plaintext authentication.

Use a publicly trusted, automatically renewed certificate for mail.example.com so MTA-STS validation succeeds. Postfix's smtpd_tls_chain_files replaces the older per-algorithm key and certificate settings.

Authentication only on the submission ports

Turn on SASL (smtpd_sasl_auth_enable = yes) only for the submission and submissions services, not on port 25. Servers delivering to you never authenticate, and offering AUTH on port 25 only invites password guessing. Dovecot's guide to Postfix SASL shows the pairing: smtpd_sasl_type = dovecot and smtpd_sasl_path = private/auth in Postfix, with a matching unix_listener inside Dovecot's service auth block.

No open relay

An open relay accepts mail from anyone, for anyone. It is the oldest mistake in email and it still happens, usually because someone widened mynetworks to "make it work". Postfix's default smtpd_relay_restrictions is permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination, which only relays for local networks and logged-in users. Use reject_unauth_destination once you have tested, and keep mynetworks to the loopback addresses. Then test from a host outside your network: an attempt to send to an external address without logging in must fail with a 5xx reply.

Rate limits and connection screening

Postfix's anvil service tracks per-client rates. smtpd_client_connection_rate_limit caps connection attempts per client per time unit, and smtpd_client_auth_rate_limit caps AUTH commands, "regardless of whether or not Postfix actually accepts those commands." Both default to 0, meaning unlimited. Set modest values on the submission services, where legitimate clients connect rarely.

postscreen sits in front of smtpd on port 25 and handles many inbound connections in one process, deciding which clients may talk to a real smtpd. It can apply pregreet tests and DNS allow and deny lists before a single SMTP command is processed.

"Fail2ban style" blocking, a log watcher that adds a temporary firewall rule after repeated failed logins, complements rate limits. It does nothing against slow, distributed guessing, so give each user a long, unique password.

Keep the stack patched

Every part of the stack ships security fixes, from the MTA and IMAP server to OpenSSL and the base images. Subscribe to each project's announcements and your distribution's security notices. Our post on SMTP abuse from open relays to SMTP smuggling shows why: protocol parsing differences between servers have produced real spoofing problems, and the fixes arrived as configuration changes and software updates that only help if you apply them.

How do you back up, migrate and monitor a mail server?

What to back up

  • Mailboxes. With Maildir, file-level backup tools work; indexes can be rebuilt. Back up from a filesystem snapshot if you can.
  • DKIM private keys, stored encrypted. Without them, a rebuilt server sends unsigned mail until you publish a new selector.
  • Configuration: /etc/postfix, /etc/dovecot, the filter's local settings and the MTA-STS policy, ideally in version control.
  • TLS certificates and the account database, if you use one.

Whatever tool you use, test a restore of one mailbox to a scratch machine. A mail backup you have never restored is a hope.

Migrating mail between servers

IMAP-to-IMAP synchronisation tools copy folders and flags between two servers with each user's credentials. Dovecot also ships doveadm sync and doveadm backup for Dovecot-to-Dovecot moves. For a cutover:

  1. Lower the MX record's TTL a day ahead.
  2. Copy all mailboxes to the new server while the old one keeps receiving.
  3. Switch the MX record, and update SPF if the sending IP changes.
  4. Run a final incremental sync for messages that arrived during the switch.
  5. Keep the old server accepting mail for a few days, since some senders cache MX lookups or retry on old addresses.

If the MTA-STS policy names the old host, publish the new host in the policy first and bump the id, because senders with a cached enforce policy will refuse to deliver to an MX that is not listed.

Monitoring the queue

Undeliverable mail waits in the deferred queue for retry. A growing queue means rejections, DNS failures or abuse. Check it with postqueue -p, read the deferral reasons in the mail log, and alert above your normal size.

Reading DMARC aggregate reports

Every receiver that supports DMARC reporting will send a daily XML report (usually compressed) to the rua address. RFC 9990 gives a sample: report_metadata names the reporting organisation and date range, policy_published repeats the policy it found, and each record holds a source_ip, a count, the policy_evaluated result for DKIM and SPF, and the raw auth_results. Read them for three things:

  • your own server's IPs passing DKIM and SPF with alignment;
  • legitimate services that send as your domain but fail alignment (a forgotten newsletter tool, a billing system); and
  • IPs you do not recognise sending as your domain, which tell you a reject policy is worth having.

Aggregate reports hold IPs and counts, not content. Failure reports (RFC 9991) can include message fragments.

Self-hosted, relayed or hosted: which setup fits?

Fully self-hostedSelf-hosted with a relayHosted mail on your own domain
Control over software and dataCompleteComplete for storage; relay sees outbound mailLimited to what the provider exposes
Inbound pathDirect to your serverDirect to your serverProvider's servers
Outbound deliverability effortHigh: static IP, PTR, reputation, monitoringLow to moderate: relay handles IP reputationLow: provider handles it
Needs outbound port 25YesNo (587 or 465 to the relay)No
Needs PTR you controlYesNoNo
Privacy at restYou hold everythingYou hold stored mailProvider holds stored mail
Privacy in transitTLS between you and recipientsRelay sees outbound mailProvider sees all mail
Patching and security workAll yoursAll yours, except the relayProvider's
Typical costServer or VPS plus your timeServer plus relay fees plus your timePer-user subscription
Failure impactYour outage means bounced or delayed mailSame for inbound; relay outage delays outboundProvider's outage
Best forPeople with a static IP and time to operate itHome servers and small domainsAnyone who wants mail to just work

Each is right for someone. Self-hosting with a relay removes the hardest problem if you want to own your data; hosted mail on your own domain keeps the option to move later, as our Gmail replacement guide discusses.

Step by step: Postfix, Dovecot, DKIM, SPF, DMARC and MTA-STS

This walkthrough builds a single-domain server for example.com on a Debian or Ubuntu host, with local system accounts as mail users, Maildir storage, Rspamd for spam filtering and DKIM signing, and mail.example.com as the hostname. Replace names and addresses with your own. Commands assume root or sudo. It does not cover installing a webmail application.

1. Check the prerequisites

Confirm with your provider that inbound port 25 reaches the host, outbound 25 is allowed (or plan a relay), and you can set the PTR.

# The hostname the server will use everywhere
hostnamectl set-hostname mail.example.com

# From another machine: is inbound 25 reachable once Postfix runs?
nc -vz mail.example.com 25

# From the server: is outbound 25 allowed? (any MX you know accepts connections)
nc -vz -w 5 mx.example.net 25

# Does the PTR for your IP match the hostname, and back again?
dig +short -x 203.0.113.25
dig +short A mail.example.com

The last two commands must return mail.example.com. and 203.0.113.25 respectively.

2. Publish the basic DNS records

mail.example.com. IN A     203.0.113.25
example.com. IN MX    10 mail.example.com.
example.com. IN TXT   "v=spf1 mx -all"
_dmarc.example.com. IN TXT   "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"

Start DMARC at p=none to read reports before enforcing. Add includes for any other services that send as your domain before relying on -all.

3. Get a certificate

Use any ACME client to obtain a certificate for mail.example.com (and mta-sts.example.com, which you will serve over HTTPS in step 8). The paths below assume the common /etc/letsencrypt/live/ layout. Set a renewal hook that reloads Postfix and Dovecot.

4. Install and configure Postfix

apt install postfix

Choose "Internet Site" and enter example.com as the mail name. Then set the core parameters in /etc/postfix/main.cf:

myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
mynetworks = 127.0.0.0/8 [::1]/128
inet_interfaces = all

# TLS for the SMTP server (inbound and submission)
smtpd_tls_chain_files = /etc/letsencrypt/live/mail.example.com/privkey.pem,
    /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes

# Opportunistic TLS for outbound delivery (default in Postfix 3.11+)
smtp_tls_security_level = may

# SASL authentication through Dovecot (enabled per service in master.cf)
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

# Relay only for local and authenticated clients
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

# Hand final delivery to Dovecot over LMTP
mailbox_transport = lmtp:unix:private/dovecot-lmtp

# Rspamd milter for filtering and DKIM signing
smtpd_milters = inet:127.0.0.1:11332
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Now enable the two submission services in /etc/postfix/master.cf. The stock file contains commented examples; uncomment and adjust them so they read:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_client_auth_rate_limit=10
submissions inet n      -       y       -       -       smtpd
  -o syslog_name=postfix/submissions
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_client_auth_rate_limit=10

Older Postfix releases name the second service smtps. Check the configuration and look for warnings:

postfix check
postconf -n | sort

If you will send through a relay, add these to main.cf and create the credentials file with mode 600:

relayhost = [smtp.relay.example]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
postmap /etc/postfix/sasl_passwd

5. Install and configure Dovecot 2.4

apt install dovecot-imapd dovecot-lmtpd
dovecot --version

Dovecot 2.4 changed its configuration syntax from 2.3, so check which version your distribution ships and use the matching documentation. For 2.4, a minimal /etc/dovecot/dovecot.conf for system users with Maildir reads:

dovecot_config_version = 2.4.0
dovecot_storage_version = 2.4.0

protocols = imap lmtp

mail_driver = maildir
mail_path = ~/Maildir

ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem

passdb pam {
}
userdb passwd {
}

# Postfix delivers with full addresses; look up the local part
protocol lmtp {
  auth_username_format = %{user | username | lower}
}

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

Validate and restart, then confirm the sockets exist where Postfix expects them:

doveconf -n
systemctl restart dovecot postfix
ls -l /var/spool/postfix/private/auth /var/spool/postfix/private/dovecot-lmtp

6. Generate a DKIM key and enable signing

Rspamd's dkim_signing module looks for keys at /var/lib/rspamd/dkim/$domain.$selector.key by default, uses the selector dkim unless told otherwise, and signs mail from authenticated users. Generate a 2048-bit RSA key with Rspamd's own tool:

mkdir -p /var/lib/rspamd/dkim
rspamadm dkim_keygen -s dkim -b 2048 -d example.com \
  -k /var/lib/rspamd/dkim/example.com.dkim.key > /root/example.com.dkim.txt
chown _rspamd:_rspamd /var/lib/rspamd/dkim/example.com.dkim.key
chmod 600 /var/lib/rspamd/dkim/example.com.dkim.key
cat /root/example.com.dkim.txt

The owner name of the Rspamd user varies by package; check it with ps -o user= -C rspamd. The output file contains the TXT record to publish. Make the defaults explicit in /etc/rspamd/local.d/dkim_signing.conf:

path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector = "dkim";
sign_authenticated = true;
allow_username_mismatch = false;
rspamadm configtest && systemctl reload rspamd

7. Publish DKIM, TLS-RPT and the MTA-STS TXT records

dkim._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=<the key from example.com.dkim.txt>"
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
_mta-sts.example.com. IN TXT "v=STSv1; id=20261024T000000"
mta-sts.example.com. IN A   203.0.113.25

A 2048-bit key exceeds 255 characters, so it is published as several quoted strings in one record; receivers join them.

dig +short TXT dkim._domainkey.example.com
dig +short TXT _dmarc.example.com
dig +short TXT _mta-sts.example.com

8. Serve the MTA-STS policy

Serve this file over HTTPS, with a valid certificate for mta-sts.example.com, at /.well-known/mta-sts.txt. Start in testing mode:

version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
curl -s https://mta-sts.example.com/.well-known/mta-sts.txt

After a couple of weeks of clean TLS-RPT reports, change mode to enforce, raise max_age (604800 seconds is one week), and change the id in the TXT record so senders fetch the new policy.

9. Test with swaks

swaks is a scriptable SMTP test client. First, prove the server is not an open relay. From a machine outside your network, without authenticating:

swaks --server mail.example.com --port 25 \
  --from test@example.org --to someone@example.net

The RCPT TO must be rejected with a 5xx reply ("Relay access denied"). Next, send an authenticated message through submission to an outside mailbox you own:

swaks --server mail.example.com --port 587 --tls \
  --auth-user alice --from alice@example.com --to you@example.net

swaks prompts for the password. To test implicit TLS, repeat the command against port 465 with swaks' TLS-on-connect option in place of STARTTLS:

swaks --server mail.example.com --port 465 --tls-on-connect \
  --auth-user alice --from alice@example.com --to you@example.net

In the received message, open the original headers and find the Authentication-Results header added by the receiving server. You want spf=pass, dkim=pass with header.d=example.com, and dmarc=pass.

Finally, confirm a remote server can deliver to you: send from an outside account to alice@example.com, then check the log and the Maildir:

journalctl -u postfix --since "10 min ago" | grep -E "status=|reject"
ls ~alice/Maildir/new/

10. Read a DMARC report and tighten the policy

Within a day or two, reports arrive at dmarc-reports@example.com. Decompress one and look at the records:

gunzip -c report.xml.gz | grep -E "<source_ip>|<count>|<disposition>|<dkim>|<spf>"

Every row from 203.0.113.25 (or your relay's IPs) should show DKIM pass and SPF pass. Investigate any legitimate source that fails before you tighten the policy. When the reports have been clean for a few weeks, move to p=quarantine, then to p=reject, which is also the order Microsoft's Outlook.com guidance advises ("none → quarantine → reject"). Add sp=reject if no subdomains send mail. If your record still contains pct=, remove it: RFC 9989 dropped the tag.

What changed and when

DateEventSource
October 2008RFC 5321 (SMTP) published, obsoleting RFC 2821RFC Editor
September 2011RFC 6376 (DKIM) published; now an Internet StandardRFC Editor
November 2011RFC 6409 defines message submission on port 587RFC Editor
April 2014RFC 7208 (SPF) published, obsoleting RFC 4408RFC Editor
March 2015RFC 7489 (DMARC) published as InformationalRFC Editor
June 2015RFC 7505 defines the null MX recordRFC Editor
January 2018RFC 8301 retires rsa-sha1 signing for DKIM; RFC 8314 prefers implicit TLS for submissionRFC Editor
September 2018RFC 8461 (MTA-STS) and RFC 8460 (TLS-RPT) publishedRFC Editor
July 2019RFC 8617 (ARC) published as ExperimentalRFC Editor
1 February 2024Gmail sender requirements take effectGoogle
February 2024Yahoo begins phased enforcement of sender standardsYahoo
5 May 2025Outlook.com enforcement for domains sending over 5,000 messages a dayMicrosoft
May 2026RFC 9989, 9990 and 9991 obsolete RFC 7489 as Proposed StandardsRFC Editor

Common mistakes

  • Two SPF records. RFC 7208 allows only one v=spf1 record per name; publishing two causes a permanent error. Merge them into one.
  • Signing with a domain that does not align. A relay that signs with its own domain gives you dkim=pass but not DMARC alignment. Sign with your own key.
  • Jumping straight to p=reject. Without reading reports first, you will bounce mail from a billing system or form handler you forgot about.
  • Leaving pct= in DMARC records. It no longer exists in RFC 9989. Use t=y while testing instead.
  • Offering AUTH on port 25. Enable SASL only on the submission services.
  • Widening mynetworks. Adding a LAN or container range to "fix" a client problem can turn the server into a relay for anything on that network. Authenticate the client instead.
  • A PTR that does not match. The PTR, myhostname, the EHLO name and the certificate name should be the same host.
  • Switching MTA-STS to enforce before the certificate or MX list is right. Senders that cached an enforce policy will refuse delivery until it is fixed or expires.
  • Not watching the queue. A deferred queue that grows for days is a delivery problem, or abuse, that you only notice when someone complains.
  • Using Dovecot 2.3 examples on Dovecot 2.4. Dovecot's upgrade notes list renamed settings (ssl_cert became ssl_server_cert_file) and split mail_location into several mail_* settings. Run doveconf -n after every change.

FAQ

Can I run a mail server from home?

Receiving works if inbound port 25 is open. Sending is harder because of port 25 blocks, residential IP reputation and fixed reverse DNS, so most home setups send through an authenticated relay on 587 or 465.

What is the difference between SPF, DKIM and DMARC?

SPF says which IP addresses may send for the envelope domain. DKIM attaches a signature that proves a domain vouched for the message and that it was not changed. DMARC checks that one of them passed for a domain aligned with the visible From: address, and tells receivers what to do and where to send reports when they did not.

Is DMARC RFC 7489 still current?

No. In May 2026 RFC 7489 was obsoleted by RFC 9989 (DMARC), RFC 9990 (aggregate reporting) and RFC 9991 (failure reporting), published as Proposed Standards. Most existing records keep working, but the pct, rf and ri tags were removed and np, psd and t were added.

Should I use port 587 or 465 for sending?

Both are submission ports for authenticated clients. Port 587 starts in plaintext and upgrades with STARTTLS; port 465 uses implicit TLS from the first byte. RFC 8314 prefers implicit TLS, so offer 465 and keep 587 for clients that need it. Port 25 is for server-to-server delivery only.

Do I need MTA-STS if I already have STARTTLS?

STARTTLS alone can be stripped by an attacker on the path, and the sending server will fall back to plaintext. MTA-STS tells senders that support it to require TLS with a valid certificate when delivering to your MX, so a downgrade fails instead of silently succeeding. Start in testing mode with TLS-RPT reports.

Why does my mail go to spam even with SPF, DKIM and DMARC passing?

Authentication proves who sent a message, not that recipients want it. Providers also weigh reputation, complaint rates (Gmail and Yahoo ask for under 0.3%) and content, and a new IP has little reputation yet.

What is a smarthost and is using one cheating?

It is an authenticated outbound relay, a normal documented configuration (relayhost in Postfix). You still sign with your own DKIM key and list the relay in SPF, so receivers can verify your domain authorized it.

How do I know if my server is an open relay?

From outside your network, try sending between two external addresses on port 25 without logging in. The server must reject the recipient with a 5xx reply, as in step 9 of the walkthrough.

Where Safeguard fits

Safeguard does not run, filter or monitor mail servers, and it does not check your DNS records, TLS settings or sending reputation. The fit here is indirect. Safeguard is a software supply chain security platform: it looks at the software you build and deploy. If you run your mail stack from container images, the CLI's image scan lists the open source components in an image and matches them against vulnerability databases; if you maintain your own webmail deployment, a plugin, or scripts around the server, the directory scan does the same for that repository:

safeguard scan --image registry.example.com/mail/filter:latest
safeguard scan --dir .

Results land as JSON under ./output, and the platform shows which of your projects contain a given component and version. That tells you about known vulnerabilities in packages; it does not test your Postfix or Dovecot configuration or your operating system packages outside an image.

A mail stack is built from open source parts: the MTA, the IMAP server, the filter, a TLS library, a webmail application with its own dependency tree, and the base images underneath. When a vulnerability lands in one of those parts you build or ship yourself, the approaches below apply.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

These demos show Safeguard working on software projects, not on a mail server. They apply to the webmail code, plugins, scripts and container images around your mail stack.

The first demo is a real Safeguard CLI session. After install, safeguard opens the interactive terminal, you ask it to fix the lodash CVE in a repository, and it reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The same ask, approve and test loop fits a webmail front end or a mail admin tool whose pinned dependencies need a bump.

Click through it at your own pace, or open it full screen.

The second demo sets up the local runner on your own machine, approves it with its device code, and then scans from the terminal. For a self-hoster, that means scanning the images your mail stack runs from happens on hardware you control.

Click through it at your own pace, or open it full screen.

The third demo is a real Android session: you send work to a computer running the CLI and approve the command on the phone with Allow once, Allow for turn or Deny. If you look after a home server while away from it, this is how you would approve a dependency update on the machine without opening a remote shell.

Click through it at your own pace, or open it full screen.

Get the apps at safeguard.sh/download and read the CLI docs at docs.safeguard.sh/docs/cli.

Quick check

A message passes SPF for bounces.relay.example and carries a valid DKIM signature with d=relay.example. The From header says alice@example.com. Does it pass DMARC for example.com?

No. Both checks passed, but neither authenticated domain is aligned with example.com, the domain in the From header. Sign with your own DKIM key (d=example.com) or use an envelope domain under example.com so at least one result aligns.

Why can a server on port 25 not simply require TLS from every sender?

Because some legitimate senders still cannot negotiate TLS, and Postfix's TLS documentation notes that RFC 2487 forbids requiring it on a publicly referenced server. Instead, offer STARTTLS opportunistically and publish an MTA-STS policy, which asks capable senders to insist on valid TLS when delivering to you.

Sources

Last reviewed: 24 October 2026. Mailbox provider requirements and mail server defaults change; check each linked page for the current version before you rely on a setting or threshold.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.