Masked Email from the command line and the API
Fastmail exposes Masked Email over JMAP, so an address is one HTTP request
away. This covers maskedemail-cli, which wraps that API, and the
methods it calls.
Install the CLI
maskedemail-cli is an open source Go client for Masked Email. Pick whichever installer you already have:
npm install -g maskedemail-cli
mise use -g go:github.com/dvcrn/maskedemail-cli@latest
go install github.com/dvcrn/maskedemail-cli@latest
Give it a token
The CLI authenticates with a Fastmail API token, the same kind the iOS app uses. Create one in Fastmail with Masked Email as its only scope; the token guide has the screens. Then put it where the CLI looks:
export MASKEDEMAIL_TOKEN=fmu1-...
maskedemail-cli session
session prints the account and capabilities the token reaches. If
it fails here, nothing else will work, and the usual cause is a token created
without the Masked Email scope. Scopes cannot be added to an existing token, so
you have to make a new one.
The commands
maskedemail-cli create [-domain "<domain>"] [-desc "<description>"] [-prefix "<prefix>"] [-enabled=true|false]
maskedemail-cli list [-show-deleted] [-all-fields]
maskedemail-cli enable <maskedemail>
maskedemail-cli disable <maskedemail>
maskedemail-cli delete <maskedemail>
maskedemail-cli update <maskedemail> [-domain "<domain>"] [-desc "<description>"]
Creating an address for a signup, then reading back what you have:
$ maskedemail-cli create -domain "example.com" -desc "Example newsletter"
$ maskedemail-cli list
Masked Email For Domain Description State
123@mydomain.com example.com Example newsletter enabled
-prefix puts a word you choose at the front of the generated
address, which makes a list of them easier to read later. Leave it off and
Fastmail picks its own word pair.
Pipe create into your clipboard and the address is ready to
paste into the signup form:
maskedemail-cli create -domain "example.com" | pbcopy on macOS,
or | wl-copy under Wayland.
What it calls underneath
Masked Email is a Fastmail extension to
JMAP, advertised by
the capability https://www.fastmail.com/dev/maskedemail. Every
JMAP client starts at the session endpoint, which returns the API URL to post
to and the account ids to use:
curl -H "Authorization: Bearer $MASKEDEMAIL_TOKEN" \
https://api.fastmail.com/jmap/session
Take apiUrl from that response, and the account id from
primaryAccounts under the Masked Email capability. Listing every
address is then one method call:
{
"using": [
"urn:ietf:params:jmap:core",
"https://www.fastmail.com/dev/maskedemail"
],
"methodCalls": [
["MaskedEmail/get", { "accountId": "u123abc", "ids": null }, "0"]
]
}
There are two methods, both standard JMAP shapes:
MaskedEmail/get reads addresses, and
MaskedEmail/set creates, updates and destroys them. Everything the
CLI does is one of those two.
The MaskedEmail object
idandemail: the address and its id, both set by the server and immutable.state:pending,enabled,disabledordeleted.forDomain: the site the address was made for, as a URL or a bare domain.description: your own note about what it is.emailPrefix: set only at creation, up to 64 characters ofa-z,0-9and underscore.createdAt,createdByandlastMessageAt: all set by the server.url: a link back to a record in your own system.
Set -appname on the CLI, or send your own client name, and it
lands in createdBy. Fastmail's web interface shows that value, so
you can tell which tool made an address.
The four states
- pending is where a new address starts, and the only state you cannot return to. It lets a client show you an address before you commit to it.
- enabled delivers to your inbox.
- disabled sends mail to Trash. The sender gets no error.
- deleted bounces mail. The sender is told the address does not exist.
So disable is the quiet option and delete is the loud
one. A deleted address can be restored from Fastmail's own settings, but mail
that bounced while it was deleted is gone.
Blocking an address covers that
choice in more detail.
The CLI passes -enabled=true by default, so
create hands back an address that is already live rather than
one sitting in pending.
Other clients
The same library backs maskedemail-js for Node, and Masked Email Manager on iOS. 1Password and Bitwarden call the same API from their signup flows, which the password manager guide covers.
Masked Email Manager is the same library with a list you can search and swipe, for when you are signing up on a phone rather than at a terminal.