Projects & Stories

Receive Email via AWS and import it into your Mailserver

This time my goal was to receive and send email via AWS. Sending mail is qickly done with your MTA but receiving mail is a bit more tricky.

First of all I configured two MX records one for AWS and one for my own server which should act as backup server:

lukas ~ > dig MX zauberstuhl.de  
[...]
zauberstuhl.de.         10800   IN      MX      50 mail.zauberstuhl.de.  
zauberstuhl.de.         10800   IN      MX      10 inbound-smtp.eu-west-1.amazonaws.com.  
[...]

After setting up the DNS records we have to create some filter rules in AWS. Now we can choose between importing the mail in the AWS-webmail, using a custom lambda function or store it in a S3 bucket.

Since I want to see and store the mail on my own server I chose S3 and
created a script which fetches the mail from S3, stores it in my local mailserver and re-run sieve filter rules on the received mail.

#!/bin/bash

/usr/bin/find /var/mail -maxdepth 1 -name '*.*' |while read -r domainPath; do
  domain=${domainPath##*/};

  mkdir -p /var/mail-aws-ses/${domain} || exit 1;
  /usr/local/bin/aws \
    s3 mv s3://<S3-BUCKET-NAME>/${domain} \
          /var/mail-aws-ses/${domain} --recursive || exit 1;

  /usr/bin/find /var/mail-aws-ses -type f |while read -r file; do
    while read -r name; do
      mail_dir="/var/mail/${domain}/${name}";
      if [ ! -f ${mail_dir}/new/${file##*/} ]; then
        mv -v $file ${mail_dir}/new;
        #/usr/bin/sieve-filter -e -W -C -u ${name}@${domain} \
        #  ${mail_dir}/sieve/rainloop.user.sieve INBOX
      fi
    done < <(grep -Po "[a-zA-Z0-9.-]+(?=@${domain})" $file |sort |uniq)
  done
done  

In this case the AWS filter rule (you created earlier) should store all mails separated by their domain name e.g. s3://<S3-BUCKET-NAME>/zauberstuhl.de/. The script will then search for different domain names in /var/mail, fetch all mail from S3 and check every single user whether they received mail or not.

In case you have multiple recipients following line grep -Po "[a-zA-Z0-9.-]+(?=@${domain}) will extract all usernames with the given domain name.

In case you have sieve filter rules; Remove the two comments and adjust ${mail_dir}/sieve/rainloop.user.sieve to your own path.

Happy hacking,
Lukas