· 27 min read

Un servidor doméstico con un aviso rojo intenta enviar correos que se estrellan contra un muro con alambre de espino y caen al suelo, mientras un sobre blanco rodea el obstáculo por el aire atravesando una nube y sigue su camino

This blog is about self-hosting things. I have written several articles about running on your own server what other people rent you by the month.

This one is about the single piece I recommend you do not self-host.

That is not a contradiction, it is what the numbers say. Standing up a mail server is the easy part: apt install postfix and ten minutes later you have one running. The problem is that running and delivering are two different things, and your server has very little say in the second one.

And it is not just me saying so. The company that sells you the server you would run it on says it in writing:

«We strongly recommend against running your own mail server, as self-hosted mail servers are difficult to secure and maintain, are frequently flagged as spam, and require constant monitoring.»
DigitalOcean documentation, checked in July 2026

By the end of this article you will have SMTP2GO connected, running for free and with tracking switched off. But first it is worth understanding what we are up against, because it decides everything else.

Why your own mail server does not deliver

Four obstacles: port 25 blocked, no reverse DNS, an IP with no history, and blocklists
All four obstacles are outside your configuration. You can have a flawless Postfix and still hit every one of them.

Port 25 is closed, and it is not your provider being awkward

Server-to-server mail travels over port 25. Almost no cloud provider will let you use it outbound:

ProviderOutbound port 25How you get it opened
AWS EC2BlockedA form, roughly 48 hours, and per region
Google CloudBlockedOnly lifted once they consider the project low risk
AzureBlocked except on EA or MCA-E contractsExemption by contract type
DigitalOceanBlocked, and 465 and 587 tooNo documented process
Hetzner Cloud25 and 465 blockedAfter a month and your first paid invoice
VultrBlocked on new instancesA ticket, and they warn they cannot promise it
Oracle CloudBlocked since June 2021A limit increase request

At home it is worse, because your ISP almost certainly blocks it as well. One thing worth getting right: RFC 5068 does not recommend blocking port 25, it explicitly declares itself neutral. The recommendation comes from M3AAWG, the industry association. What the RFC does require: providers may not block port 587 on you.

Your IP has no history, and that costs you

Google and Microsoft have never seen your IP address. Before anyone trusts it you have to warm it up, sending little and ramping slowly. Amazon puts that at two to six weeks depending on the receiving provider.

For a sense of how seriously the people who do this for a living take it, look at SendGrid’s warm-up schedule: they start at twenty emails an hour and do not reach 211 until a week later. A freshly installed Postfix does exactly the opposite: it sends everything you throw at it from the first second.

And there are lists that include you without you doing anything wrong

Spamhaus’ Policy Blocklist covers more than 1.4 billion IPv4 addresses, close to 40% of the routable space. They clear up the misunderstanding themselves: «IPs in this set are not necessarily bad; they simply should not be sending email». If your provider declared that range as non-sending, you are in it before you have sent a thing.

UCEPROTECT is worse: its level 3 lists entire autonomous systems. They admit it without flinching: «may, and probably will, cause collateral damage to innocent users». And the same people sell delisting by subscription through another site. Your neighbour in the IP range decides your deliverability.

If you follow a tutorial telling you to put reject_rbl_client dnsbl.sorbs.net in your Postfix, that tutorial has been out of date for two years: SORBS shut down on 5 June 2024 and its zones are empty.

The alternative: a relay, and why the free tier is plenty

A transactional mail relay is a service that takes your messages over SMTP and delivers them from its own IPs, which have years of reputation behind them and teams paid to keep it that way. You skip all four problems at once.

The interesting part is that transactional mail from an internal service is a tiny volume. Signups, password resets, notifications that somebody shared something. For a team of fifteen that is dozens of emails a month, not thousands. It fits inside any free tier with room to spare.

These are the August 2026 numbers, taken from each provider’s own pricing page:

ProviderFree tierCard requiredLog retentionCatch
SMTP2GO1,000/month, 200/dayNo5 daysFive sender domains
Mailgun3,000/monthNo1 dayOne sender domain
Elastic Email3,000/month, 100/dayNoLimitedTheir branding on the footer
Resend3,000/month, 100/dayNo3 daysHas SMTP, but no SMTP logs to debug with
Brevo300/dayNoLimitedTheir branding on the footer
SendGridGoneYesN/A60-day trial only
Amazon SESGone for new accountsYesN/ASandbox until approved

The last two rows need a warning, because most comparisons you will find still recommend them:

The rest of this article being about SMTP2GO does not mean it is the best one. Several in that table are fine, and the choice depends on your situation: Mailgun gives you triple the volume, so does Elastic Email, and none of the three asks for a card. I use SMTP2GO because the signup is one of the simplest to write up, and because the procedure is nearly identical everywhere: verify the domain with a couple of DNS records, get the credentials, put them in your application. If you follow this article with a different provider, you will recognise every step.

That said, two things about it I do like, and that are worth checking on whichever one you pick. It allows five sender domains instead of one, and it keeps five days of logs instead of one. That second one matters more than it sounds: when somebody tells you on Monday that they never got Friday’s invitation, one day of history leaves you nothing to look at.

And one detail about its limits, which behave differently from each other: go over the daily cap and mail is queued and goes out later. Go over the monthly one and it is rejected and lost.

Would you rather I set one of the others up? Leave me a comment and I will write that one.

Signing up, step by step

Let us do the practical part first, which is ten minutes. Afterwards I explain why what you are about to build works, which is what actually helps you the day something does not arrive.

SMTP2GO pricing page with the Get Started button under the free plan
The free plan asks for no card and does not expire.

Once you have confirmed your email, the first thing is to register the domain you will send from. There is a decision here worth understanding:

SMTP2GO panel with no sender domains yet and the button to add one
A sender domain lets you send from any address on that domain. A single sender, only from that one address.

For an internal service you want a sender domain, so you can use passbolt@, uptime@ or whatever else without coming back here. The free plan allows five.

SMTP2GO offering to set the DNS records up automatically or by hand
If your DNS is on Cloudflare, GoDaddy or similar, it writes them for you. If not, you add them by hand, and they are exactly the same three records.
Entri dialog asking for one-off permission to write the records into Cloudflare
The permission is one-off and scoped to this domain. Entri handles it, acting as the bridge to Cloudflare.

A minute later the records are in place:

The three CNAME records created in Cloudflare by SMTP2GO
The three CNAMEs created. Look at the middle one, because we are not keeping it.

The third record: the one I delete

Table: two required authentication CNAMEs and one optional tracking CNAME
Two of the three are authentication. The third has nothing to do with whether your mail arrives.

The link CNAME exists so SMTP2GO can rewrite every link in your emails and route them through its tracking system to count clicks. It is the same mechanism marketing tools use, and for that it is fine. For an internal service’s notifications, I have three reasons not to create it.

This is the serious one, and it is not about deliverability but about things simply working.

Corporate filters open the links in your emails before delivering them. Microsoft Safe Links documents it plainly: «URLs are scanned prior to message delivery». Barracuda, Proofpoint and Mimecast do the same.

Now think about what a signup or password reset link is: it only works once. If a scanner visits it before the person does, it is already used. This is not theory, it is documented by the identity vendors themselves: NextAuth has a whole page about the problem and describes it without ambiguity, «effectively consuming it». Supabase warns about the same thing and names Safe Links. Auth0 recommends using codes instead of links outright.

Adding a tracking domain that rewrites every link means putting one more hop on a path that is fragile already. I do not do it.

Diagram of the four steps by which a mail filter uses up a signup link
The four steps. The failure is neither in your service nor with your user, which is exactly why it is so hard to find.

Two: the number that justifies tracking is not reliable any more

Open tracking works with a transparent one-pixel image. Since iOS 15, Apple’s Mail Privacy Protection downloads that remote content «upon receipt of the message rather than when viewing it». Which means the pixel fires whether or not anybody opened anything. Gmail, for its part, has served images through its own proxy since 2013, so the IP and browser you record are not your user’s.

The definitive line comes from Google itself, in its sender guidelines: «Google does not track open rates», adding that low opens «are not necessarily a reliable indicator of delivery problems».

Three: shared tracking domains end up blocked

When tracking runs through a shared domain, you share its reputation too. Netcraft documented a phishing campaign built on a large provider’s click tracking, with at least nine customer accounts compromised. Spamhaus has a specific code for this in its domain list: 127.0.1.103, «abused redirector domain».

And there is a fourth reason that is no longer technical: in 2026 both the Italian and the French data protection authorities published guidance requiring prior consent for tracking pixels. The French one does explicitly exempt transactional mail tied to a service the user asked for. Which is exactly our case, but better not to have the argument at all.

How to remove it

You delete it from your own DNS, not from SMTP2GO:

Cloudflare asking to type DELETE to confirm removing the link CNAME
Select the link CNAME and delete it. Cloudflare makes you type DELETE to confirm.
Cloudflare showing only the two authentication CNAMEs remaining
The two that matter are left, which are the authentication ones.

And now the part that had to be checked, because theory is one thing and the provider not getting upset is another. Back to SMTP2GO, hit verify again, and this is what comes out:

SMTP2GO showing the domain verified and the tracking domain disabled
Domain verified. Tracking domain, disabled. Exactly what we were after.

The domain stays verified, mail keeps going out authenticated, and the panel simply marks tracking as disabled. No drama.

Checking it came out right

Before connecting anything, check the DNS looks the way you want it: the two authentication records resolving, and the tracking one resolving nothing at all. Swap the identifier for yours, which is the one SMTP2GO gave you:

# The bounce one: has to return return.smtp2go.net
dig +short em799236.itrafa.com CNAME

# The DKIM one: has to return a key, not an empty line
dig +short s799236._domainkey.itrafa.com TXT

# And the tracking one must return NOTHING
dig +short link.itrafa.com CNAME
rafa@homelab: ~
$ dig +short em799236.itrafa.com CNAMEreturn.smtp2go.net. the envelope now carries your name $ dig +short s799236._domainkey.itrafa.com TXTdkim.smtp2go.net."v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A…" the key is published $ dig +short link.itrafa.com CNAME(nothing) and that is the point: I deleted it
All three dig commands are real, run against itrafa.com’s DNS. Two in place and one gone.

If the first one does not return return.smtp2go.net., or the second does not return a key, the record is mistyped or DNS has not propagated yet. If the third returns anything, the tracking one is still alive. And with all three like that, it is time to understand why this works without touching anything else on your domain.

Why you never touch your domain’s SPF or DMARC

You have the three records in place and checked. Here is what they do, and why nothing else needs changing.

Every email carries two senders. The From: header, which is the one your user sees, and the envelope sender, the MAIL FROM, which travels in the Return-Path and only servers ever see. SPF validates the envelope one, not the one your user sees: RFC 7208 is explicit about it and advises against checking other identities.

The first CNAME puts that envelope in your name. By creating em799236.yourdomain.com pointing at return.smtp2go.net, the receiver checks SPF against your subdomain and, following the CNAME, ends up reading SMTP2GO’s record. Your root SPF never comes into it, which is why it can stay on -all with only Microsoft 365 inside.

DMARC adds one more condition: the domain SPF validated has to align with the one in the From:. In relaxed mode, which is the default (aspf=r), sharing an organisational domain is enough, and em799236.yourdomain.com and yourdomain.com do. The second CNAME does the same job on the DKIM side: the signature goes out with d=yourdomain.com. As long as one of the two aligns, DMARC passes the message, so your policy can stay at p=reject untouched.

Diagram: SPF is checked against the envelope sender, which the CNAME points at SMTP2GO
Checked with dig on a live domain that runs Microsoft 365 and has DMARC at p=reject.

Put another way: the relay’s messages authenticate using records that hang off your domain but whose contents SMTP2GO maintains. You publish two pointers and they handle the rest, key rotation included.

Do not add SMTP2GO to your SPF record. Besides being unnecessary, it is risky: SPF has a hard limit of ten DNS lookups and Microsoft 365 already spends several. Going over does not fail «a bit», it returns permerror, and that does not take down the relay’s mail: it takes down SPF for your entire domain, corporate mail included.

One note for anyone going to look things up: DMARC changed specification in 2026. RFC 7489 is obsolete, and where there was one document there are now three: RFC 9989, which also obsoletes 9091, plus RFC 9990 for aggregate reports and RFC 9991 for failure reports. The change most likely to affect you: the pct= tag is gone, which was the standard way to roll DMARC out gradually. In its place comes t=, the test mode, and the underlying change is that there is no percentage rollout any more: either you apply the policy or you do not. You still scope with sp= and np=.

The four details you are going to need

The DNS records authenticate your domain, but they are not what you send with. For that you need credentials, and they live somewhere not entirely obvious: in the SMTP2GO panel, under Sending → SMTP Users.

You create a user there and the service hands you a password. That gives you the four details:

SMTP2GO panel under Sending, SMTP Users, with the Add SMTP user button and the connection details
Sending → SMTP Users. Note the box on the right: the server and the ports are right there, no documentation hunt needed.
DetailValue
Servermail.smtp2go.com
Port587. If your network blocks it, 2525. With implicit TLS: 465
UsernameThe one you created under SMTP Users
PasswordThe one it generated for you right there
The Add SMTP User form with username, password, description and rate limit
The signup form. This is where the password appears, and it appears in the clear: SMTP2GO never shows it to you again and does not email it to you.

And mind the password, because this is the moment. SMTP2GO shows it in the clear here and only here. Copy it into your password manager before you leave this screen. If you lose it there is no recovery, it generates a new one, and that means touching the configuration of everything that was already sending with the old one.

All eight ports, and which one to actually use

The panel gives you a list of eight ports. I checked them one by one before writing this: all eight accept connections, all eight negotiate TLS 1.3, and on all eight I got as far as authenticating, cutting the conversation before sending anything. You can verify the encryption yourself with this:

Terminal showing an openssl loop checking all eight SMTP2GO ports with TLS 1.3
The loop checks the five STARTTLS ports. The three implicit-TLS ones behave the same, minus that flag.

The port number does not decide the encryption, the protocol does. On 25, 587, 2525, 80 and 8025 the session starts in the clear and upgrades to TLS with STARTTLS. On 465, 443 and 8465 it is encrypted from the first byte, with no preceding phase. Which is why all eight come back with TLS 1.3 up there: 2525 is not «the unencrypted port», it is a 587 with a different number.

That said, they are not fully interchangeable, and the criteria are these:

And remember the first section: the one blocking port 25 is your provider, not SMTP2GO. Them having eight ports open does not mean you can get out through all eight.

Check this before you configure anything

This takes thirty seconds and saves you an entire afternoon. Before touching the application, find out which ports the server you are installing it on can actually get out through. If the one you picked is filtered, you will not find out from a clear error message: you will find out because nothing arrives, and you will start checking the password, which was fine.

No need to install nc or telnet. /dev/tcp is a redirection built into bash itself and it is always there:

for p in 25 587 2525 465; do
  if timeout 5 bash -c "</dev/tcp/mail.smtp2go.com/$p" 2>/dev/null; then
    echo "  $p  open"
  else
    echo "  $p  BLOCKED"
  fi
done
rafa@homelab: ~
$ for p in 25 587 2525 465; do> timeout 5 bash -c "</dev/tcp/mail.smtp2go.com/$p" 2>/dev/null \> && echo " $p open" || echo " $p BLOCKED"> done  25 open 587 open 2525 open 465 open
Real output from this blog’s server, where all four get out. If your provider filters one, that line takes the full five-second timeout and says BLOCKED.

It reads itself: if it answers instantly, that port gets out. If it takes the whole five seconds and says BLOCKED, that port is filtered and there is nothing to configure there, you either ask for it to be opened or use another one. And if everything comes back blocked, check whether your outbound firewall is allowlist-based, which is more common than you would think on corporate networks.

Three settings on the form, and one costs you half your quota

The signup goes through without touching any of these three. They are worth a look anyway.

Set a sending limit, even if you do not need one

The form has a Rate Limit field, and it comes with Use default ticked, which on a new account means unlimited. Untick it and put a number in.

Which number: look at what that service actually sends and multiply by five. If your site sends twenty notifications a day, set it to a hundred. It will never get in your way in normal use, and the day a runaway loop fires at three in the morning, it stops there instead of eating the month’s thousand emails. A cap is not a restriction, it is a fault detector that also stops the fault.

Turn tracking off here as well

Further up I explained why I delete the third CNAME, the tracking one. As it turns out, the switches also live on each user, under the Tracking & Status tab. Turning Open Tracking and Click Tracking off here is belt as well as braces, and it is what makes your links go out exactly as you wrote them.

The Tracking and Status tab with open tracking and click tracking switched off
The two tracking switches, per user. Off, your links travel without being rewritten.

The audit copy doubles what you use

Under Advanced there is an option that looks like a gift: Email Auditing, which blind-copies everything you send to whatever address you give it. Sounds like a safety net. But read the small print, which is right there: those copies count towards your monthly quota. Meaning you switch it on and go from 1,000 emails to 500 real ones.

Next to it is Bounce Notifications, which is worth switching on: it emails you every time a message bounces. That is the difference between finding out the next day and finding out in August.

The Advanced tab with email auditing BCC and bounce notifications
The audit copy, with its warning: every blind copy costs you one send from the plan.

One per service, not one for everything

Last decision, and the one you thank yourself for most over time. You can create several SMTP users at no cost, so create one for each thing that sends and give it a description that means something: website, backups, Uptime Kuma.

The reason is containment, and it fits with the cap above. An SMTP credential lives in the clear in the config file of every service that uses it: in wp-config, in docker-compose, in the backup script. Anyone who can read that file walks away with it. And with that credential they cannot just send: they can send as your domain, signed and aligned, which is exactly what we have spent half an afternoon setting up.

With one shared credential, that day means rotating it and reconfiguring everything that sends mail on your network at once, while the rest stays broken. With one per service, you revoke that one and you are done. And if each carries its own cap, whoever walks off with one cannot go past that number: the damage has a ceiling before you even find out. As a side effect, the activity log tells you which user sent what, so «who sent this?» has an answer.

The SMTP users list showing the newly created user and its description
The user created. The description is not decorative: it is what tells you which one to revoke a year from now.

Send a test email before touching your application

This step saves you the pointless afternoons. Do it and you know for certain whether the problem is in the relay or in your application’s configuration, instead of guessing.

curl speaks SMTP, so there is nothing else to install. Swap in your credentials and your address:

curl --url 'smtp://mail.smtp2go.com:587' --ssl-reqd \
  --user 'YOUR_USERNAME:YOUR_PASSWORD' \
  --mail-from '[email protected]' \
  --mail-rcpt '[email protected]' \
  --upload-file - <<'EOF'
From: Alerts <[email protected]>
To: [email protected]
Subject: SMTP2GO test

If you are reading this, the relay works.
EOF
rafa@homelab: ~
$ curl –url 'smtp://mail.smtp2go.com:587' –ssl-reqd \ –user 'YOUR_USERNAME:YOUR_PASSWORD' \ –mail-from '[email protected]' \ –mail-rcpt '[email protected]' \ –upload-file – <<'EOF'From: Alerts <[email protected]>To: [email protected]Subject: SMTP2GO test If you are reading this, the relay works.EOF $ echo $?0 With -v, the line that matters:< 250 OK id=1wvJyX-AIkwcC8t2TP-6Pwa look that id up in Reports → Activity And in the received message, Show original:SPF: PASS with IP 1.2.3.4DKIM: PASS with domain itrafa.comDMARC: PASS
Actually run against the relay. curl prints nothing at all when it works: the confirmation is the 0.

The --ssl-reqd is not decoration: it forces the connection to be encrypted and fails if the server does not offer it. Without it, curl would send your credentials in the clear if something went wrong.

If the message arrives, the relay is fine and whatever is left to sort out is in your application. If it does not, check the log under Reports → Activity in the panel: it shows you whether the message went out, whether it bounced and why. Remember that on the free plan that history lasts five days.

And while you have it in front of you, open it and hit Show original. Those are the three lines that close the loop: if SPF, DKIM and DMARC all say PASS, the records you set up are doing their job. If DKIM passes but with a domain that is not yours, the second CNAME is wrong. And if DMARC fails while the other two say PASS, that is an alignment problem, which is what the previous section explains.

If your domain already uses Microsoft 365 or Google Workspace

This is the situation of almost any small company, and the scariest one: you already have corporate mail working and you do not want to break it by adding a relay for four notifications.

You are not going to break it, and you do not have to touch anything you already have. I checked it on a live domain sending through Microsoft 365, with SPF ending in -all and DMARC at p=reject, which is the strictest configuration available. SMTP2GO’s mail goes through regardless, for the reason you saw in the alignment section.

The one thing worth being careful about is the sender. Always send from an address on your own domain, something like [email protected]. If you put a From: from another domain, the DMARC in charge is that other domain’s and your configuration does not protect you.

The date worth putting in your calendar

You have it built now, so this is about why you will need it beyond the service you just connected. You may also have arrived at this article the other way round: because something stopped sending without anybody touching anything. If that is you, this will sound familiar.

Plenty of organisations have applications and devices sending with the username and password of a corporate account, pointed at Microsoft’s or Google’s SMTP server. The most common case is an account created for exactly that, something like [email protected], set up by somebody the day the multifunction printer arrived. That is ending, and the two providers are moving at different speeds.

Timeline of the shutdown of password-based SMTP in Google Workspace and Microsoft 365
Both dates on one axis. Google sits to the left of today; Microsoft, four months to the right.

Google: this already happened

Google has already switched off what it called «less secure apps», in stages between mid-2024 and the first half of 2025. Its documentation puts it plainly: «CalDAV, CardDAV, IMAP, SMTP, and POP will no longer work with legacy passwords».

And a taste of how hard these timelines are to follow: Google publishes four different shutdown dates across four of its own official pages (30 September 2024, January 2025, 14 March 2025 and 1 May 2025). I am not going to pick one and pretend it is the right one. What matters is that it is off today.

And one nuance that changes the diagnosis: Google did not close SMTP. What it stopped accepting is the account password. App passwords still work, so a device can be reconfigured. The problem is that somebody has to know that and do it.

Microsoft: yours happens in December

This one still works, which is exactly why it is worth reading now and not in January. The official timeline, which replaces an earlier and more aggressive one, is this:

WhenWhat happens
Now to December 2026Nothing changes
End of December 2026Disabled by default for existing organisations. An administrator can still turn it back on
Organisations created afterwardsNot available by default. OAuth as the supported method
Second half of 2027The final removal date gets announced

In other words: if you have something sending with the username and password of a Microsoft 365 account, you have until the end of December. After that it stays re-enablable by hand, but you are swimming against the tide, and in 2027 they announce the end of it. One note for anyone inclined to trust the deadline: this date has already slipped twice, from September 2025 to April 2026 and from there to December. That it has moved twice is not a reason to skip preparing, it is a reason not to leave it to the last month.

Microsoft offers a replacement of its own called High Volume Email, and it is worth knowing what it is before somebody suggests it: it is for internal recipients within your organisation, and only that. For sending a notification to a customer it is no use. It is also billed from 1 June 2026, at $42 per million recipients, and without a billing policy assigned the account simply will not send.

Why this always gets discovered through a ticket

I have seen the same pattern several times, and it is what makes this change hurt more than it should. Nobody monitors the thing that has worked for years.

The classic case is the printer that had been scanning to email for six years without anybody touching it. It was set up by somebody who has since left, with the password of an account nobody remembers, and it worked. One day it stops, and the systems team does not find out from an alert or a dashboard: they find out because tickets start coming in from people saying the scanner no longer sends anything.

And that this is not a hobby horse of mine is what the industry itself says: Ricoh published a formal notice in May 2025, updated in February 2026, listing which functions stop working (scan to email, internet fax, notifications) and on which models. Xerox has another, with OAuth-capable firmware already available and no hardware change needed. If your estate is either of those brands, you have homework with names on it.

The same goes for backup notifications, the contact form on your site, the alarm system’s alerts and any automation somebody set up years ago. They all share one property: nobody looks at them until they break, and when they break they do not tell you, they just stop sending.

This is where a relay stops being a convenience and becomes the sensible option. Those credentials do not depend on any person’s account, they do not expire with corporate mail policy, and if they need rotating tomorrow you rotate them in one place and that is that. It is the difference between an inventory and a surprise.

And now, connect it

You have the relay working and verified. What is left is putting those four details into each service, and that does change depending on which one.

The next article I publish is the Passbolt one, where I connect it end to end. It is the perfect case for this: without working email, Passbolt will not let you create a single user.

Self-hosting makes sense for almost everything. For outbound email the sums do not add up: weeks of fighting blocklists and IP warm-up, only to deliver worse than a service that charges you nothing. Handing this one off is not giving up. It is choosing where you spend your afternoons.

More from IT Rafa