
In this series, we’ve seen how including an S/MIME signature is fairly straightforward. Sending S/MIME encrypted mail is more complex because you need to obtain recipient public keys. It’s one thing when you’re using a mail client for humans such as Thunderbird – but how can that work with app-generated email streams?
Business in a box.
Discover our solutions.
Talk to our sales team
In part 1, we had a quick tour of S/MIME, looking at signing and encryption of our message streams across a range of mail clients. Part 2 took us through a simple command-line tool to sign and encrypt emails, then send them through SparkPost. Part 3 showed how to inject secure mail streams into on-premises platforms such as Port25 PowerMTA and Momentum.
In this series, we’ve seen how including an S/MIME signature is fairly straightforward. Sending S/MIME encrypted mail is more complex because you need to obtain recipient public keys. It’s one thing when you’re using a mail client for humans such as Thunderbird – but how can that work with app-generated email streams?
But wait – there is another way into Mordor to get those keys. Your service can invite your customers (via email, of course) to send you back a signed mail to a known customer-service address. Using the magical powers of SparkPost Inbound Relay webhooks, we’ll extract and store that public key for you to use.
We can summarise this in a simple use-case:
As a recipient of messages, I provide your service with my personal email signature via email, so that in future, emails can be sent to me in S/MIME encrypted form.
From this, let’s derive some more detailed requirements:
We need an always-on, reliable inbound email service to receive those signed emails.
There should be no special requirements on the mail format, other than it should carry an S/MIME signature.
Because anyone can try to send a mail to this service, it should be designed defensively, for example, to reject “spoof” messages from bad actors. There will need to be several layers of checking.
If everything checks out OK, the service will store the certificate in a file, using the well-known plain-text Privacy-Enhanced Mail (PEM) format.
There are some non-functional requirements:
Machine-to-machine webhook services can be hard to see just from responses to what’s happening inside. The service should provide extensive human-readable application-level logs. In particular, the certificate parsing and checking should be logged.
We add test cases for the app internals, using the nice Pytest framework, and run those tests automatically on check-in using Travis CI integration with GitHub.
OK – let’s get started!
1. Solution overview
Here’s what the overall solution will look like.

2. Installing, configuring and starting the web app
3. SparkPost inbound relay webhooks setup
Firstly, we select a domain to use as our inbound message address – here, it will be inbound.thetucks.com. Set your domain up following this guide. Here are the steps I used in detail:
3.1 Add MX Records
You’ll need access to your specific Internet Service Provider account. When done, you can check them with dig – here’s the command for my domain.
dig +short MX inbound.thetucks.com
You should see:
10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com.
3.2 Create an Inbound Domain
Use the SparkPost Postman API collection, selecting the Inbound Domains / Create .. call. The body of the POST request contains your domain, for example:
{ "domain": "inbound.thetucks.com" }

3.3 Create a Relay Webhook
Create an inbound relay webhook using the relevant Postman call. The message body in my case contains:
{ "name": "Certificate Collection Webhook", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }
As mentioned before, I recommend setting an auth_token to your own secret value, as set in the webapp.ini file on your host.
Your “target” value needs to match your host address and TCP port where you’ll be hosting the web app.
Your “domain” value needs to match your MX records set up in step 1.

That’s it! The plumbing is done. You should now be able to send certificates to your inbound address, they will be processed and show up on your web application host – in this case, a file named bob.lumreeker@gmail.com.crt.
Now you can send encrypted emails to Bob, using the tools described in parts 2 & 3 of this series.
You can examine the contents of a certificate using:
openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout
4. Internals: DKIM checking, certificate validation
The app checks received emails have valid DKIM and checks that the certificates themselves are valid, as described here. There are implementation notes in there too, and ideas for further work.
Summing up…
We’ve seen how recipient public keys can be gathered easily using an email to an inbound relay webhooks address. Once done, those recipients can receive their messages in S/MIME encrypted form.
That’s it for now! Happy sending.