Email in Sandstorm

This tutorial will show you how to setup your personal sandstorm instance with support for e-mail.

First, a quick rundown of how email works in sandstorm. Sandstorm is running an SMTP server on port 30025 that will accept email of the form publicId@hostname. publicId is randomly generated for every grain that handles e-mail, and hostname is extracted from the BASE_URL parameter in sandstorm.conf (which is initially created by the installer script). Outgoing e-mail is sent through an external SMTP server, controllable by the SMTP Url configuration under Admin Settings (the MAIL_URL parameter in sandstorm.conf has been deprecated). When sending e-mails, the only valid "From" addresses are the grain's generated publicId@hostname address, or the verified email from the user's account (e.g. the e-mail address obtained via Google or Github login). The interfaces for sending/receiving e-mails are available in hack-session.capnp.

Outgoing SMTP

All you need to do is configure the SMTP Url field under Admin Settings to a working SMTP server that will accept e-mails with the SMTP envelope's bounce address set to your grain's local address. If running at home, you can usually use your ISP's SMTP server. Otherwise, Sendgrid, Mailgun, and Mandrill also provide such services, some with free tiers. The SMTP Url looks like this:

smtp://USERNAME:PASSWORD@SMTP_HOST:SMTP_PORT

If USERNAME is in the form of an email address, like user@example.com, then the @ will need to be URL-encoded as %40.

Receiving email into Sandstorm app instances

Prerequisites

  • A personal domain at which you are running your Sandstorm server.
  • Basic knowledge of how to configure DNS records for your domain.
  • nginx
  • A working outgoing SMTP server.

Setup DNS

This is relatively straightfoward if you know how to configure your domain's DNS records. All you need to do is add an MX record pointing to your sandstorm server.

Proxy SMTP

Sandstorm's SMTP server runs on port 30025, and is intended to sit behind a reverse proxy. The easiest way to do accomplish this is with nginx. Add the following to your nginx.conf:

mail {
    ssl_certificate /etc/keys/my-ssl.crt;
    ssl_certificate_key /etc/keys/my-ssl.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
    ssl_prefer_server_ciphers on;

    server {
        listen 25;
        server_name sandstorm.example.com;
        auth_http localhost:8008/fake-smtp-auth;
        protocol smtp;
        timeout 30s;
        proxy on;
        xclient off;
        smtp_auth none;
        starttls on;
    }

    server {
        listen 465;
        server_name sandstorm.example.com;
        auth_http localhost:8008/fake-smtp-auth;
        protocol smtp;
        timeout 30s;
        proxy on;
        xclient off;
        smtp_auth none;
        ssl on;
    }
}

nginx requires that you provide an authentication handler for all SMTP proxies. We don't actually need authentication because our server is only meant to receive e-mail destined for this host (it will not relay). So, we have to set up a fake authentication handler. In the part of your nginx config where you defined your HTTP servers (e.g. /etc/nginx/sites-available/default), add this fake server for SMTP auth purposes:

# Fake SMTP authorizor which always accepts. Put this in your http block.
server {
    listen 127.0.0.1:8008;
    server_name localhost;

    location /fake-smtp-auth {
        add_header Auth-Server 127.0.0.1;
        add_header Auth-Port 30025;
        return 200;
    }
}