All systems operational Amsterdam · Paris · Reykjavík +5 Pay with Cryptocurrency
Networking & self-hostingAdvanced21 min readUpdated 2026-08-31

Run a mail server that reaches the inbox

Installing the software is an afternoon. Convincing the rest of the internet to believe your server is the actual work — and it is settled by four DNS records and one address’s history before anyone reads a word you sent.

Run a mail server that reaches the inbox
On this page
  1. Why self-hosted mail lands in spam, and it is almost never the software
  2. The four records, and what each one actually proves
  3. What you need before you start
  4. Choosing a stack, honestly
  5. Step-by-step
  6. Warming up an address nobody has vouched for yet
  7. The address is the asset — keeping it off blocklists
  8. What self-hosting your mail does not give you
  9. Jurisdiction, the account, and paying without a card
  10. Frequently asked questions

The message leaves your server, the log says 250 2.0.0 Ok, and it lands in the spam folder anyway. Nothing failed. Nothing is going to tell you what went wrong either, because a receiving gateway is under no obligation to explain itself and has every incentive not to — explaining the filter is how you teach people to evade it. That silence is what makes self-hosted mail feel unfixable, and it is why most people abandon it after a fortnight and go back to paying somebody else to be trusted on their behalf.

The fix is almost never in the mail server. It is in four DNS records — one of which cannot be set at your registrar at all — and in the history of the IPv4 address you were handed, a history you did not write and usually cannot see. So this guide does the records first and the software second: what each one actually proves to a gateway, the alignment rule that quietly breaks setups that look perfectly correct, how to get a PTR that matches in both directions, and how to warm an address nobody has vouched for yet. Then the part the tutorials leave out — what self-hosting your mail genuinely buys you, and what it does not.

Why self-hosted mail lands in spam, and it is almost never the software

Postfix is not the problem. It has been delivering mail competently since 1998 and it will do exactly what you configure it to do. The problem is that SMTP grants no standing to anyone by default, so a receiving gateway has to decide whether to believe an unknown server — and it makes that decision in a fixed order, mostly before your message is examined at all:

  • The connecting IP, first and hardest. Before your server has said anything beyond EHLO, the gateway has already looked the address up in public blocklists (Spamhaus SBL, XBL, PBL and CSS, Barracuda, SpamCop) and in its own private reputation store, which also tracks the surrounding /24 and the ASN. A listed address is refused at connection time with a rejection you may never see if nobody is reading the logs.
  • The name that address claims. A missing PTR gets connections refused outright by several large providers. A generic provider-assigned PTR of the ip-203-0-113-10.example-host.net variety is worse than it looks — it is the exact signature of consumer lines and unattended boxes, which is where botnets live.
  • Authentication. SPF, DKIM and then DMARC, evaluated in that order and combined by the alignment rule in the next section. This is where a setup that looks right on paper usually fails.
  • Only then, the message. Content heuristics, list hygiene, the complaint rate you generate, and how recipients behave over the following weeks.

Three of those four are decided before a single byte of your content is scored, which reframes the whole exercise: you are not writing better emails, you are building a credential. The two largest receivers have written the minimum down, so there is no guesswork about the floor. Every sender needs SPF or DKIM, valid forward and reverse DNS, TLS on the connection, and a spam-complaint rate under 0.3%; anything sending in bulk needs SPF and DKIM and a DMARC record with alignment, plus one-click unsubscribe. Treat that as the entry fee rather than the goal.

The four records, and what each one actually proves

Each record answers a different question, and the useful way to hold them in your head is by what a forger would have to control to fake it.

  • PTR — who owns the address agrees with you. The reverse zone for an IP is delegated to whoever holds the allocation, which is why this is the one record you cannot add at your registrar. A PTR pointing at mail.example.com, plus an A record for mail.example.com pointing back at the same IP, is FCrDNS — forward-confirmed reverse DNS. It proves the address holder and the domain holder are the same party, or at least on speaking terms.
  • SPF — this server was allowed to send for this envelope. A TXT record listing the hosts permitted to send for a domain. The trap is scope: SPF authenticates the envelope sender (the MAIL FROM, which becomes Return-Path) and the HELO name. It says nothing whatsoever about the From: header your recipient actually reads, which is why SPF alone has never stopped anyone impersonating you.
  • DKIM — this message was signed by a domain and has not been altered. Your server signs selected headers and the body with a private key; the public half sits in DNS at <selector>._domainkey.<domain>. Unlike SPF it survives being forwarded, because the proof travels inside the message rather than depending on which IP delivered it.
  • DMARC — and this is the one everybody gets wrong. DMARC does not merely require that SPF or DKIM passed. It requires that a passing mechanism be aligned with the domain in the visible From: header. Relaxed alignment accepts a matching organisational domain (so mail.example.com aligns with example.com); strict alignment demands an exact match.

That alignment rule is worth stating on its own, because it produces the single most exasperating support thread in self-hosted mail: a message can pass SPF, pass DKIM, and still fail DMARC — when both passed for a domain that is not the one in From:. It happens the moment mail leaves through a relay that rewrites the envelope, or when a bundle signs with its own hostname instead of your domain. Everything looks green in your logs and the message is still quarantined. Read the alignment, not the pass.

What you need before you start

Less hardware than you would guess, and more commitment than you would like.

  • A domain you intend to keep. Reputation attaches to the domain as firmly as to the address, and it accrues over months. A domain you might drop next year is not worth warming.
  • A modest plan, sized for filtering rather than for mail. Message delivery costs almost nothing; spam filtering and indexing cost RAM. Cub (1 vCPU / 2 GB / 40 GB NVMe, $5.00/mo) runs Postfix, Dovecot and Rspamd for one domain and a handful of mailboxes without complaint. Scout (2 vCPU / 4 GB / 70 GB, $9.00/mo) is the honest floor for a containerised bundle that also wants ClamAV and a search index. Disk is the part that grows, so size it for the archive rather than for today.
  • A dedicated IPv4 with no history, and a routed IPv6 /64. Every plan ships both. This is the component you cannot fix later with configuration, and the reason recycled budget-cloud addresses are a false economy for mail.
  • Outbound port 25. Open on every plan, with no unblocking ticket to file. The acceptable-use policy forbids unsolicited bulk mail and open relays, which is precisely what keeps the ranges deliverable for everyone sending legitimately.
  • Debian 13 from the template library, and a jurisdiction chosen deliberately. Mail is not latency-sensitive, so pick the location for where the mailbox should legally sit rather than for a few milliseconds.

Choosing a stack, honestly

There are three shapes, and picking the wrong one is how weekends disappear.

  • Assembled by hand. Postfix as the MTA, Dovecot for IMAP and authentication, Rspamd for filtering and DKIM signing. Perhaps two hundred lines of configuration in total, all of which you can read and none of which is hidden. Most control, most understanding required, and the version this guide assumes.
  • A bundle. mailcow is feature-complete and container-based, and genuinely wants 4 GB before it is comfortable. Mail-in-a-Box is opinionated and pleasant if you accept its choices exactly. Stalwart is a single binary that covers SMTP, IMAP, JMAP and filtering in one process, and is by some distance the lightest of the three. All of them install in an hour; none of them will do your DNS for you.
  • A relay you do not run. If the requirement is “my application must send password resets” and there will never be a mailbox, an MTA is the wrong shape entirely. Configure a smarthost and spend the afternoon on something else.

The stack does not decide your deliverability. It decides how much of your Saturday it costs. Everything that determines whether your mail arrives happens in DNS and in the reputation of one address — which is the whole of the next section.

Step-by-step

  1. Choose one hostname, and get the forward DNS right first

    Pick a single canonical name for the server — mail.example.com is conventional and there is no reason to be clever. Publish its A record (and AAAA, if you will send over IPv6) pointing at your VPS, then point the domain’s MX at that name. An MX must name a host, never an IP literal and never a CNAME; gateways that reject the latter are within their rights and several do.

    dig +short A    mail.example.com
    dig +short AAAA mail.example.com
    dig +short MX   example.com

    Do this before requesting the PTR, not after. Reverse DNS is verified in both directions, and a PTR pointing at a name that does not yet resolve is worse than having no PTR at all.

  2. Deploy, harden, and make the system hostname match

    Deploy Debian 13 from the template library and give it the usual ten minutes of basic hardening before anything listens on a public port: key-only SSH, root password login disabled, nftables default-deny, unattended security upgrades. Then set the hostname to the name you just published, because the HELO your MTA announces should equal the PTR you are about to request.

    hostnamectl set-hostname mail.example.com
    hostname -f
    apt update && apt full-upgrade -y

    hostname -f must print the full name. If it prints the short one, add the fully-qualified name to /etc/hosts ahead of the short alias. Then open only what mail needs: 25 inbound for server-to-server delivery, 587 and 465 for your own authenticated submission, 993 for IMAP over TLS.

  3. Request the PTR record, then verify the loop in both directions

    The reverse zone belongs to whoever holds the allocation, so this is a request rather than a DNS edit: ask for the PTR from the client area for your dedicated IPv4, and for the specific /64 address you will send from if you intend to use IPv6. It costs nothing and is live within the hour. Then confirm the loop closes:

    dig -x 203.0.113.10 +short
    dig +short mail.example.com

    The first must return mail.example.com, the second must return 203.0.113.10. That agreement is FCrDNS and it is the baseline the rest of your authentication is judged against. Set exactly one PTR per address — multiple names for one IP is a legacy pattern that confuses gateways rather than impressing them. If you cannot keep IPv6 rDNS straight, bind outbound delivery to IPv4 only; the large receivers are measurably stricter over v6, and a v6 send from an address without a matching PTR is refused where the v4 equivalent would merely have been scored.

  4. Publish SPF, and stay under the ten-lookup limit

    One TXT record at the domain apex, listing what may send for it. Two SPF records on one domain is a permanent error rather than a merge, so check for an existing one before adding yours.

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

    mx authorises whatever your MX resolves to, which is the server you just built. The constraint to respect is that SPF permits a maximum of ten DNS-resolving terms during evaluation: each a, mx, include: and redirect= costs one, and every include: also spends whatever its target spends, recursively. Exceed ten and the result is permerror, which most receivers treat as no SPF at all — a spectacular way to break authentication by adding a vendor.

    Use ~all (softfail) while you are still discovering which systems send as you, and move to -all (fail) once your DMARC reports have been quiet for a fortnight. Verify with:

    dig +short TXT example.com
  5. Generate a DKIM key and publish the selector

    2048-bit RSA is the sensible default. Name the selector so that rotating it later is possible — a date-based name such as s2026a costs nothing now and saves an awkward afternoon in a year.

    mkdir -p /var/lib/rspamd/dkim
    rspamadm dkim_keygen -s s2026a -b 2048 -d example.com \
      -k /var/lib/rspamd/dkim/example.com.s2026a.key
    chown _rspamd:_rspamd /var/lib/rspamd/dkim/example.com.s2026a.key

    The command prints the public half as a TXT record to publish at s2026a._domainkey.example.com. A 2048-bit key does not fit in a single 255-character DNS string, so it has to be split into several quoted strings within the one record. Most DNS interfaces do this silently and correctly; a few do not, and the result is a key that looks published and never verifies. Confirm what the world actually sees:

    dig +short TXT s2026a._domainkey.example.com
  6. Roll DMARC out in three stages, never in one

    Start in observation mode. The policy does nothing yet; the reports are the entire point.

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

    Leave it at p=none for two to four weeks and actually read the aggregate reports that arrive — they are XML, and a viewer makes them legible in seconds. You are looking for sources you had forgotten: the invoicing system, the CRM, the forum that sends as your domain. Every one of them needs to be authorised or moved before you tighten anything.

    Then step up: p=quarantine; pct=25, widen the percentage as the reports stay clean, and only then p=reject. Going straight to p=reject on day one is how people discover, expensively and in public, that their own billing platform was never aligned. Forensic reports (ruf=) are largely ignored by the big receivers on privacy grounds, so do not build a process that depends on them.

  7. Install the stack, and close the relay before you open the port

    Install Postfix, Dovecot and Rspamd — or the bundle you chose — and then, before anything faces the internet, settle the one question that decides whether your address survives the week. Port 25 must accept mail only for the domains you host. Everything outbound goes through authenticated submission on 587 or 465. In Postfix that is one line, and its order matters:

    smtpd_relay_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_unauth_destination

    Then prove it from somewhere else on the internet, because testing an open relay from the server itself proves nothing:

    swaks --to postmaster@example.org \
          --from probe@example.net \
          --server mail.example.com

    You want that refused with a relay-access denial. An open relay is discovered by scanners within hours, burns the address permanently, and is forbidden by the acceptable-use policy for exactly that reason.

  8. Test the way a gateway does, then begin the warm-up

    Send a real message to an account you control at each of the large providers and read the full headers of what arrived, rather than trusting a score out of ten. The Authentication-Results header is the receiver telling you precisely what it concluded:

    Authentication-Results: mx.google.com;
      dkim=pass header.d=example.com;
      spf=pass smtp.mailfrom=example.com;
      dmarc=pass (p=NONE) header.from=example.com

    Three passes are necessary but not sufficient — check the domains as well. header.d, smtp.mailfrom and header.from all naming the same organisational domain is what alignment looks like when it is working. If dmarc reads fail while SPF and DKIM both read pass, you have found the misalignment described earlier and the fix is in whichever domain is the odd one out.

    With that clean, add MTA-STS and TLS-RPT if you want the modern polish, and start sending for real — small, consistent, to people who will reply.

Warming up an address nobody has vouched for yet

An address with no reputation does not start neutral. A gateway’s prior for an unfamiliar datacentre IP that has suddenly begun sending is closer to “probably unwanted”, because that is what the overwhelming majority of such addresses turn out to be. Warm-up is the process of replacing that prior with evidence, and it cannot be rushed by any technical means.

  • Start small and climb slowly. Tens of messages a day in the first week, roughly doubling every few days, reaching normal volume over two to four weeks. A sender that goes from zero to a thousand overnight is indistinguishable from a compromised host, and gets treated as one.
  • Engagement outweighs volume. Messages that are opened, replied to and moved out of spam by real people are worth far more than throughput. Send to the recipients most likely to interact first — yourself, colleagues, correspondents who already know you.
  • Be consistent. Two hundred messages one day and nothing for three weeks never builds a stable profile. A steady trickle beats an erratic burst at the same monthly total.
  • Keep complaints under control. The published threshold is 0.3%, and above it nothing else you do matters much. Below 0.1% is where you want to live.
  • Do not mix streams. Newsletters and password resets on one address means a marketing complaint rate dragging your account recovery into the spam folder. If separating them is worth it, a second dedicated clean IPv4 is $2.00/mo with its own rDNS.

The address is the asset — keeping it off blocklists

Configuration is reproducible in an hour. Reputation takes months and can be destroyed in one evening by a compromised contact form. Treat the address as the thing you are actually protecting.

  • Monitor rather than react. Check the majors on a schedule instead of after a complaint — our walkthrough of checking whether an IP is blacklisted covers which lists carry weight, how to read a listing and how delisting actually works.
  • Rate-limit your own outbound. A cap in the MTA is what stands between a compromised script and ten thousand messages leaving before you wake up. This single setting has saved more addresses than any filter.
  • Retire hard bounces immediately. Repeatedly delivering to dead addresses is a spam-trap signal, and recycled spam traps are exactly how legitimate senders end up listed.
  • Read postmaster@ and abuse@. They are required to exist and they are where you find out about a problem before a blocklist does. Both large receivers also publish free reputation dashboards for domains you have verified; they will tell you things no public list ever will.
  • Do not fight a fight you inherited. If the address turns out to be carrying a listing that predates you, or is blocked somewhere that matters commercially, request a swap from the client area rather than spending three weeks in delisting queues for somebody else’s history.

Why the address arrived clean in the first place is the other half of this. High-churn budget clouds recycle IPv4 through enormous numbers of short-lived customers, so a “new” address routinely arrives pre-owned in every sense that matters to a gateway. Every plan here ships a dedicated, screened address rather than a slice of a shared pool — what a clean IP actually means sets out the definition and how to verify it yourself before you rely on it.

What self-hosting your mail does not give you

The honest accounting, because a guide that only lists the wins is advertising.

  • It does not make your mail private. SMTP encrypts hop by hop and opportunistically; the receiving provider decrypts and reads everything you send to their users, exactly as before. If confidentiality of content is the goal, that is end-to-end encryption, not a server you own.
  • It does not hide the metadata. Who, to whom, when, how often and the subject line all traverse the network intact — and now your own server logs them too, on a machine you are responsible for.
  • It does not free you from the large receivers. You are still asking two companies to accept your mail, and they still set the terms unilaterally. Self-hosting moves the control point; it does not remove it.
  • It does not run itself. Certificates renew, keys want rotating, disks fill, and a mail server that quietly stops accepting mail loses messages that senders will not retry forever. This is a service with an on-call dimension, however small.
  • It does not make the machine anonymous. A mail server is arguably the most self-identifying thing you can run, because publishing your domain in DNS and standing behind it is the entire mechanism. A no-KYC signup limits what your host knows about you; it does nothing about what a recipient can see. We set out the distinction properly in is a crypto-paid VPS really anonymous, and it is worth ten minutes before you assume otherwise.

Jurisdiction, the account, and paying without a card

Once the records are right and the address is warm, everything left is about where the mailbox lives and who knows it is yours.

Jurisdiction decides who can compel disclosure. A mail server is a searchable archive of correspondence, which makes location a more consequential choice here than for almost any other service. Our footprint is eight locations across the Netherlands, France, Romania, Bulgaria, Sweden, Iceland, Switzerland and Malaysia, and no US-style takedown notice carries force in any of them. That is operational policy stated plainly, not legal immunity — a binding order from a competent local court still applies, and there is a hard abuse floor we do not move. Offshore hosting explains the difference without the marketing.

The account is the part people skip. Signup takes an email address for credential delivery and nothing else — no ID, no card, no postal address, no phone number. There is no verification document to hand over later because none was ever collected; what no-KYC hosting means covers the limits of that honestly.

And the payment. A card ties a server to a bank record and a legal name held in a database neither of us controls. Checkout here settles on chain, with Monero treated as a first-class option rather than an afterthought: paying for a VPS with XMR walks the whole flow, and buying without a credit card covers getting there from no crypto at all. Deploy takes about sixty seconds after confirmation.

Which matters more here than for a disposable box. A mail server is a long commitment to one domain and one address — the reputation you are about to spend a month building is not portable. Decide the jurisdiction, the account and the payment before the warm-up, not after.

Frequently asked questions

Is outbound port 25 open, or do I have to ask for it?

Open on every plan, with no unblocking request to file and no probationary period. The trade is the acceptable-use policy: no unsolicited bulk mail and no open relays, which is what keeps the address ranges deliverable for everyone else sending legitimate mail. The IP you are assigned is dedicated and screened rather than drawn from a shared outbound pool, which is the part that cannot be added later.

SPF, DKIM and DMARC all pass and my mail still goes to spam. Why?

Because authentication proves who sent a message, not that anyone wants it. Once the records are right, what is left is reputation: the age and history of the address, the age of the domain, your complaint rate and whether recipients engage. Check two things before assuming the worst. First, alignment — a green SPF for the wrong domain still fails DMARC, so compare header.from against smtp.mailfrom and header.d in the received headers. Second, whether you have actually warmed the address, because a correct configuration sending its first hundred messages is still an unknown sender.

Do I really need a dedicated IP just to send mail?

For anything that matters, yes. On shared outbound you inherit every neighbour’s complaint rate and every listing they earn, with no way to separate your traffic from theirs. Every plan here includes one dedicated clean IPv4 with custom rDNS and a routed IPv6 /64; a second address is $2.00/mo if you want to split transactional mail from bulk. The exception is genuinely low volume with no deliverability requirement, where a relay is simply less work.

How long does warming up a new address take?

Two to four weeks to reach normal volume for a small sender, and the ramp matters more than the total. Begin in the tens per day, roughly double every few days, and prioritise recipients who will open and reply over recipients who merely receive. Consistency beats bursts — a steady daily trickle builds a stable profile where the same monthly volume delivered in one afternoon does not.

Should I just use a relay or smarthost instead?

Often, yes, and it is worth being honest about it. If the requirement is outbound notifications from one application and you will never want a mailbox, a smarthost delivers better on day one for a fraction of the effort. Self-host when you want to own the mailbox and the archive rather than the SMTP socket. The hybrid is also legitimate: run your own server for receiving and IMAP, relay outbound through an established sender, then move sending in-house once the address has warmed.

Do I need reverse DNS on IPv6 as well?

Only if you send over IPv6 — but if you do, it is not optional. The large receivers apply noticeably stricter rules to v6, and a v6 connection from an address with no matching PTR is refused where the v4 equivalent would only have been scored down. PTRs on your routed /64 are free from the client area. If keeping v6 rDNS correct is more than you want to manage, bind outbound delivery to IPv4 and leave v6 for inbound.

Can I move an existing mail server here and keep my reputation?

Domain reputation travels with you; IP reputation does not, because it belongs to the address you are leaving behind. Plan for a second warm-up rather than a cutover: stand the new server up, get FCrDNS and authentication passing, then shift sending across in slices over a fortnight while the old sender stays live. Keep DMARC at p=none or quarantine through the move and raise it again only once the aggregate reports from the new address are clean.

Deploy an offshore VPS in about a minute

No-KYC, crypto-paid, all-NVMe. Pick a tier, pay in Monero or any major coin, and get root in roughly 60 seconds.

Fenrir on guard