I’m moving my mail server on prem (read: to the basement). One of the complexities is that inbound messages lose their IP address due to NAT/port forwarding. Since I’m already using #AWS #SES for delivering email to work around my ISP blocking port 25 outbound, I wanted to try to use SES for receiving incoming mail. It took a few hours, but I eventually got it set up and working.
I had already configured an SES identity for koehn.com in order to manage outbound email. For inbound, I decided to test with a subdomain while I worked through the bugs. I wound up creating:
1. An SES RuleSet to deliver testmail.koehn.com mail to an #SNS topic.
2. A #Lambda function to receive these messages and send them to an HTTP API I created. The Lambda function handled errors that occurr by putting messages in an #SQS queue with a few minute delay. The same Lambda is triggered by the SNS topic and the SQS queue.
3. An HTTP API hosted in my email infrastructure. Written in Node.js, it receives the message from the Lambda and stores it in a Postgres table that acts as a queue. The messages are then de-queued by the same, run through Rspamd for spam analysis, and then either discarded or sent to Dovecot for storage. Again, any errors processing a message put it back on the queue for later processing. The service is run in my existing k3s infrastructure.
This architecture not only handles the problem of NAT losing sender IP information, but it’s far more resilient than anything I can self-host (or even my previous cloud versions). SES will be up nearly all the time, and messages will sit there in the queue when my servers at home offline. Once they’re back up, messages will flow through again.
Setting it all up involved (re-)learning #Lambda, #Node, #IAM, #SQS, #SNS, and a bunch of APIs. Still, I’m elated with how well it all worked out. It’s highly resilient and manages to leverage cheap AWS services (total cost should be less than $0.25/month) while avoiding the spendy ones.