Tech

Building Our Own SMTP Server: Under the Hood with Haraka

Aug 6, 2025

Overview

At Expedock, we ran into a pretty frustrating issue: some of our larger emails just weren’t making it through to our Google Groups. After digging into it, we found the culprit—SendGrid has a hard cap of 30 MB per email, while Google Groups can handle up to 50 MB. That mismatch was quietly blocking important messages from getting delivered.

So, we decided to take matters into our own hands. We built and deployed our own SMTP server—lightweight, reliable, and fully in our control—using an open-source Node.js project called Haraka.

In this post, we’ll break down the why, how, and what of our Haraka setup: why we chose it, how we built it, how it works under the hood, and the edge cases we ran into along the way.

Why?

When we were weighing our options, here’s what we looked at:

  • Amazon SES: Solid service but capped at 40 MB per email—and there’s no way to raise that limit.

  • Postfix: Super powerful and battle-tested, but a bit too heavy and complex for what we needed.

  • aiosmtpd: Great for dev and testing, but not something we’d trust in production

That led us to Haraka:

  • It’s open source

  • Built with Node.js

  • Plugin-based, so it’s super flexible and easy to customize

All of that made Haraka a perfect fit for our needs: something lightweight and reliable that could handle large emails and give us full control—without piling on operational complexity.

Understanding the Basics: SMTP + Email Authentication

SMTP, or Simple Mail Transfer Protocol, is the go-to method for sending emails over the internet. Any time an email is sent, there’s a sender and a receiver, and each has two parts working together: a user agent (your email app) and a mail server (the behind-the-scenes engine).

Source: https://www.afternerd.com/blog/smtp/

The user agent is just the email app you use—like Gmail, Outlook, or Yahoo Mail. The mail server is what actually sends your email out into the world. For example:

  • Gmail uses smtp.gmail.com

  • Outlook uses smtp-mail.outlook.com or smtp.office365.com

  • Yahoo uses smtp.mail.yahoo.com

Here’s how it works: the sending mail server says “hello” to the receiving server and they go through a quick handshake to establish a connection. Then the email gets sent over line by line, and when it’s done, the server drops a single period (.) on its own line to say, “That’s it!” After that, the connection is closed.

Before jumping into how Haraka (an open-source SMTP server) handles things, it’s good to know how email authentication works. These tools help make sure your email isn’t flagged as spam—or worse, marked as fake.

  • SPF (Sender Policy Framework): Think of this as a guest list—it tells receiving servers which IP addresses are allowed to send mail for your domain.

  • DKIM (DomainKeys Identified Mail): This one adds a digital signature to your emails to prove they’re really from you and haven’t been messed with.

  • DMARC (Domain-based Message Authentication, Reporting & Conformance): This sets the rules for what to do if an email fails SPF or DKIM checks—like send it to spam or block it completely.

If you don’t set these up properly, even legitimate emails (especially forwarded ones) might get tossed into the spam folder.

Haraka Architecture: Plugin-Powered Flexibility

At the heart of Haraka is its plugin system—pretty much everything runs through plugins, which makes it super flexible. Here’s how we set up ours:

Core Configuration:

  • smtp.ini: Where we set the basic SMTP settings

  • outbound.ini: Takes care of forwarding emails

  • log.ini and loglevel.ini: Control how logs are formatted and how much detail we get

Plugins We Used (and don’t):

  • rcpt_to.in_host_list: Helps Haraka recognize emails meant for our internal domains

  • tls, dkim, spf: Add essential layers of security and authentication

  • smtp_forward: We skipped this one—instead, we used Haraka’s outbound module for more control

One of the key things we customized: instead of using smtp_forward, we rebuild the outgoing email ourselves using Haraka’s outbound module. This gives us the flexibility to forward emails exactly the way we want—especially when routing them through our internal comms channel.

Infrastructure: From Haraka to Google Groups

We set up Haraka in its own dedicated AWS account, completely separate from our main infrastructure. Here’s a quick look at how we structured the SMTP server setup on AWS:

Here are a few extra setup steps we took to get everything running smoothly:

  • Unblocked Port 25: Since SMTP traffic runs over port 25, we had to request AWS to unblock it.

  • Set up rDNS (Reverse DNS): We mapped our Elastic IPs to domain names to help avoid getting flagged as spam.

  • Added SPF and DKIM records: We manually configured these in Route 53 to make sure our emails pass authentication checks.

  • Whitelisted in Google Groups: We made sure our new SMTP server was allowed to send mail to our internal Google Groups without issues.

Migration Steps

  1. Linking the Main Domain to the Haraka Domain

    We already had a subdomain set up to receive emails for document ingestion. Originally, it lived under our main domain in AWS Route 53, and all the DNS records pointed to SendGrid webhooks.

    With the new Haraka setup in a separate AWS account, we linked that subdomain to the Haraka domain and rerouted all email traffic to go through Haraka instead. AWS has a helpful guide on how to route traffic for subdomains.

  2. Parsing Emails from Haraka

    Our work didn’t stop at email delivery. The format of the data we get from Haraka is totally different from what we were used to with SendGrid.

    SendGrid gave us nicely structured JSON, with all the metadata parsed out. Haraka, on the other hand, gives us the raw .eml file. So, we built our own EML parser to extract the pieces we care about and connect it with our existing document ingestion pipeline.

  3. Swapping MX Records

    Once everything was ready, we updated the MX record priorities in Route 53. This made sure all emails sent to our ingestion subdomain now go to Haraka, not SendGrid.

The best part? Nothing changes for our users—they keep sending documents to the same email address. Everything else just works behind the scenes.

Handling Edge Cases

1. .eml Attachments

A .eml file is basically a saved email file—it follows a standard format called RFC-822. What makes it handy is that it stores everything about an email in one place: the headers, the message body, any attachments, and even what types of files those attachments are. Sometimes, .eml files can get a bit tricky. They can include nested attachments, meaning an email inside an email (yep, kind of like email-ception), and those inner emails might also have their own attachments.

Now, tools like mail-parser are built to dig into these nested .eml files and try to pull everything out. But for our needs, we want to keep things simple: we only care about the actual attachments from the main email—the top-level one—and we want to ignore anything that’s tucked away inside another .eml file. Our fix:

  • Recursively extract Content-IDs

  • Filter attachments based on those IDs

This keeps our processing clean and focused on just the files that matter.

2. Outlook’s "Forward as Attachment"

When someone forwards an email as an attachment in Outlook, it wraps the original message inside a .eml file and attaches it. The catch? That .eml attachment often doesn’t come with helpful metadata—there’s usually no Content-ID or even a filename—making it a bit trickier to identify and handle automatically.

Our approach:

  • Generate a fallback filename based on the subject

  • Create our own Content-ID to manage attachments

3. Oversized Emails (>50 MB)

Our SMTP server can handle emails bigger than 50 MB, but for our use case, we keep things strict: if an email is over 50 MB, we reject it right away with a standard SMTP 550 error. This helps us avoid messy situations like partial deliveries or failures later down the line.

Key Learnings

  • Owning the whole SMTP flow gives us unmatched flexibility—especially when it comes to handling tricky edge cases and building custom workflows.

  • Haraka’s plugin system makes it super easy to extend functionality and debug issues when they pop up.

  • And of course, having proper email authentication in place (SPF, DKIM, DMARC) is key to making sure our emails actually get delivered.

Conclusion

By building our own SMTP server with Haraka, we’ve eliminated dependency on third-party services that limit email size—and taken back full control over our email pipeline. Whether you need to forward huge attachments or want to avoid silent delivery failures, Haraka is a solid, production-ready solution that you can customize to fit your setup perfectly.

References

© Expedock 2025. All Rights Reserved.

Our social media

© Expedock 2025. All Rights Reserved.

Our social media

© Expedock 2025. All Rights Reserved.

Our social media