Ghstmail
Email aliases that forward to your real inbox, so you never hand over the real address.
ghstmail.space2025

What it does
You create an alias, put it in a signup form, and mail sent to it forwards to your real inbox. The site never learns your real address. If an alias starts getting spam, you switch it off or delete it.
There are three ways in: the dashboard, a Chrome extension that makes an alias on whatever site you are on, and a command line tool:
npm install -g ghstmail
ghstmail new shopping --expires 24h
Everything the command line does goes through the same HTTP API, so it can all be scripted.
How it works
Mail for the domain arrives at a Haraka SMTP server. A plugin accepts anything addressed to an alias and hands it to the backend, which looks the alias up, checks it is active and the sender is not filtered, and forwards the message to the owner. Aliases can expire, which a background worker handles.
The hard part: replying without giving yourself away
Forwarding in is the easy half. The hard half is replying. If you answer a forwarded message from your own mail client, the reply would normally go out from your real address, which is the one thing the service exists to hide.
So every forwarded message carries a reply address with a token in it. A reply sent there comes back to the server, which works out which alias and which sender the token belongs to and sends the reply on from the alias. The other person only ever sees the alias.
Threads were the second half of that problem. Mail clients group a conversation by message IDs, and a forwarded message gets a new one. The server keeps a map from each original message ID to the forwarded one, and sets the reply headers from it, so a conversation stays one thread on both sides.
Storing as little as possible
Ghstmail stores no email content. There is no command to read your mail, because there is nothing to read. At one point I found that the table of reply tokens was still keeping the subject line of every forwarded message, which the privacy policy said was never stored. The backend stopped writing it and a migration cleared what was already there.