Running my own mail server on Oracle (and the port 25 saga)

I wanted hello@akrammh.com to come from a server I own. Oracle had opinions about port 25.

Sections (8)

Every contact form on the internet promises to get back to you. Mine brags that it went through my own mail server. That one line cost me more evenings than I’d like to admit.

Why bother

Google Workspace exists. It’s cheap, it works, and nobody has ever been fired for choosing it. But I already had an Oracle Cloud server running this site, and I wanted to understand how email actually works instead of paying someone every month so I never have to find out.

That’s the honest reason. The other reason is that “I run my own mail server” is a very satisfying sentence to say out loud. I love the look people get when they hear it, somewhere between curious and slightly concerned, right before the questions start.

Email in one paragraph

Think of it as a post office. Your mail server is the sorting office. DNS (Domain Name System) records are the signs outside telling the world how to deal with you:

  • MX (Mail Exchanger) says where to deliver your post.
  • SPF (Sender Policy Framework) lists which vans are allowed to carry mail in your name.
  • DKIM (DomainKeys Identified Mail) is the wax seal proving a letter really came from you.
  • DMARC (Domain-based Message Authentication, Reporting and Conformance) is a note to every other post office saying what to do when a letter turns up without the right seal.

Get any of these wrong and your email doesn’t bounce. It quietly goes to spam. Which is worse, because nobody tells you.

The setup

I went with Stalwart, a modern mail server that runs in a single Docker container. Older setups glue three or four separate programs together for sending, receiving, spam filtering and storing mail. Stalwart does all of it in one box, which suits a server that’s already doing five other jobs.

The plan:

  1. Point mx.akrammh.com at the server.
  2. Add an MX record so mail for akrammh.com goes there.
  3. Open the mail ports.
  4. Create two mailboxes: akram@ for humans, hello@ for the robots.

Step 3 is where most Oracle tutorials lose people. Oracle has two firewalls: one in the cloud console, and one inside the server itself, because their Ubuntu images block almost everything by default. Open a port in one and not the other and it looks exactly like you did nothing.

Luckily, this wasn’t my first time. I’ve already hosted n8n, a few MCP (Model Context Protocol) servers and Twenty, an open-source CRM (Customer Relationship Management) tool, on the same kind of setup. The two firewalls and I have met.

The port 25 saga

Port 25 is how mail servers talk to each other, using SMTP (Simple Mail Transfer Protocol). Receiving on it is fine. Sending on it is a different story.

Oracle blocks outbound port 25 at the edge of its network. Not in Stalwart, not in Docker, not anywhere you can configure. I knew this going in, so the plan always included a relay: a service whose only job is carrying outgoing mail the last mile.

But I’m curious, so before setting the relay up I sent one email directly, just to see.

It sat in the queue. And sat. Stalwart kept politely trying to hand it to Gmail, and Oracle kept quietly dropping it before it left the building. No error worth reading, no bounce. Just a very patient email going nowhere.

Experiment over, relay on.

The relay

I started with SMTP2GO. Stalwart still does everything else: it hosts the mailboxes, receives all incoming mail, signs outgoing mail with my own DKIM key and keeps copies of what I send. The relay only carries the final hop.

Is that still self-hosted? Mostly. It’s like saying you cook from scratch while quietly buying the bread.

There’s a real upside, though. A fresh cloud IP (Internet Protocol) address has no sending history, and Outlook in particular treats strangers with suspicion. A relay’s addresses are already trusted. This server sends booking confirmations, and a confirmation in the spam folder is just a missed meeting with extra steps.

Next on the list is switching to Oracle’s own Email Delivery service. Its free allowance is bigger than SMTP2GO’s 1,000 emails a month. I don’t send anywhere near either limit. But more is more, and everyone understands that. It also keeps the whole setup under one roof.

One domain or two

My first plan sent automated mail from a subdomain, hello@mail.akrammh.com, so that if the robot emails ever got flagged, the main domain would keep its reputation. That’s good advice for companies sending thousands of emails a day.

This site sends a few a day, on a busy day. The subdomain meant doubling every DNS record to protect against a problem I don’t have. I dropped it. One domain, two mailboxes.

Did it work?

Both mailboxes show up in the Gmail app over IMAP (Internet Message Access Protocol, the way mail apps read a mailbox that lives somewhere else). Stalwart has no webmail, so you bring your own app. Mail to Gmail and Outlook lands in the inbox, not spam. mail-tester.com gave it 8.8 out of 10, which I’m choosing to read as a B+ rather than “room for improvement.”

DMARC is still on p=none, the “tell me about problems but don’t act on them” setting. Once the reports show everything passing for a few weeks, it moves up to quarantine.

If you’re about to try this

  • Check whether your provider blocks outbound port 25 before you do anything else.
  • On Oracle, open ports in both firewalls.
  • Plan for a relay from day one. At portfolio volume it’s free.
  • Run a test through mail-tester.com before you give your new address to anyone important.

The contact form on this site goes through all of it. If you’ve sent me a message and I replied, that’s two things working.