Skip to content

Masked email

An address given to a website tends to spread: it is sold, leaked in a breach, or added to marketing lists, and once it has spread it cannot be taken back. Masked addresses limit the damage. A masked address is a receiving address that delivers to an existing account without revealing the account’s real address.

A user can hand a different masked address to every website or service. When one of them starts sending unwanted mail or leaks the address, the user disables that address alone, and every other address keeps working. An application such as a password manager can create a masked address over JMAP when the user registers a new login, and record which site it was issued to.

Each masked address is a MaskedEmail object that belongs to one account, found in the WebUI under Account › Masked Addresses.

Masked addresses receive mail only. They cannot be used as a sending identity or as the SMTP envelope sender, so replies from the user carry the user’s own address.

The server generates the address when the object is created, and stores it in the read-only email field. The address has the form <prefix>.<code>@<domain>, with three parts:

  • <prefix> is 16 random lowercase letters and digits, or the value given in emailPrefix at creation.
  • <code> is generated by the server. It identifies the masked address and encodes its optional expiry time, set at creation with expiresAt. Because the expiry is part of the address, it cannot be changed afterwards.
  • <domain> is the domain given in emailDomain, or, without it, the domain of the account’s name.

When mail arrives for an address of this form, the SMTP server recognises it at RCPT TO, before any lookup in an external directory. It delivers the message to the owning account if all of the following hold:

  • The masked address exists and enable is true.
  • Its expiry time, if any, has not passed.
  • The account still has an address in the recipient’s domain.

Otherwise, the address is treated as an unknown recipient, and rejected like any address that does not exist on the server, as described in RCPT stage.

The message is delivered to the account as addressed. The masked address remains visible in the To header, so the user can see which address a message was sent to, and therefore which site gave it out.

Users create masked addresses in the account manager of the WebUI. Integrators, such as password managers, create them over JMAP with x:MaskedEmail/set, under the urn:stalwart:jmap capability. The following fields describe the address, and are set by the client:

FieldPurpose
descriptionA note for the user about what the address is for.
forDomainThe site the address was issued to, for example https://example.com. Password managers fill it in automatically.
urlA link back to the integrator’s entry for the address, for example a custom URI that opens the password manager at that login.
emailPrefixOptional prefix of the generated address: 1 to 64 ASCII letters, digits or underscores, not starting with an underscore. It is stored in lower case.
emailDomainOptional domain of the generated address. It must be a domain in which the account has an address.
expiresAtOptional time after which the address stops receiving mail.

emailPrefix, emailDomain and expiresAt are read at creation only, because they become part of the generated address. The server sets accountId, createdAt and, from the credentials used for the request, createdBy.

The following request, as a password manager might send it, creates a masked address for a newsletter subscription:

{
"methodCalls": [
[
"x:MaskedEmail/set",
{
"create": {
"new1": {
"description": "Newsletter signup",
"forDomain": "https://example.com",
"emailPrefix": "newsletter"
}
}
},
"c1"
]
],
"using": ["urn:ietf:params:jmap:core", "urn:stalwart:jmap"]
}

The response returns the generated address in email, for example newsletter.<code>@example.org. The same object is created from the command line with this command:

Terminal window
stalwart-cli create MaskedEmail --field description='Newsletter signup' --field forDomain=https://example.com

Creation fails when the requested address cannot be built, or when the account has no room for another one:

ErrorDescriptionCause
forbidden on emailDomainThe specified domain is not valid for this account.The domain does not exist, or the account has no address in it.
forbidden on emailDomainNo valid domain is available for this account.emailDomain is omitted and the account name has no domain.
invalidProperties on emailPrefixThe prefix does not meet the rules above.
overQuotaYou have exceeded your quota of <n> masked addresses.The account has reached its limit.

The number of masked addresses an account may hold is set by maxMaskedAddresses on the Email singleton, 5 by default. A maxMaskedAddresses entry in the account’s quotas overrides the server-wide value for that account, as described in Quotas.

Disabling an address does not free its place. Disabled masked addresses count towards the limit until they are destroyed.

An address can be retired in three ways, which differ in whether it can come back. Setting enable to false makes the address unknown at once, so mail sent to it is rejected, while the object, with its description and site, is kept. Setting it back to true restores delivery. Destroying the object removes the address permanently. An expired address is rejected in the same way as a disabled one.

Masked addresses do not outlive their account. When the account is deleted, its masked addresses are destroyed with it.

The following commands disable a masked address and delete another one:

Terminal window
stalwart-cli update MaskedEmail <id> --field enable=false
stalwart-cli delete MaskedEmail --ids <id>

To review what an account holds, x:MaskedEmail/query with an accountId filter lists its masked addresses. The MaskedEmail reference lists the remaining commands.

Each operation requires its own permission: sysMaskedEmailGet, sysMaskedEmailQuery, sysMaskedEmailCreate, sysMaskedEmailUpdate and sysMaskedEmailDestroy. The built-in User role holds all five, so every user can manage the masked addresses of their own account without help. The System Administrator role holds them as well, and tenant administrators hold them through the User role. Permissions describes how roles are assigned.