Privacy aliases are not disposable email addresses
Apple Hide My Email, Firefox Relay, SimpleLogin and friends forward to an inbox people keep for years. Here is how to tell them apart from throwaway inboxes.
A common bit of signup hygiene is a list of disposable email domains: Mailinator, 10 Minute Mail and the thousands of lookalikes that hand out an inbox nobody owns and that disappears within the hour. Blocking those is reasonable. The mistake is letting that list, or a homemade regex, sweep up privacy aliases as well. They look odd, they hide the person's main address, and they come from a domain the person didn't choose, but they behave very differently.
What the common ones look like
Apple Hide My Email. When someone uses Sign in with Apple and chooses to hide their address, Apple creates a unique address at @privaterelay.appleid.com for your app, and it forwards to the address on their Apple Account. Apple's developer documentation says relay addresses end in @privaterelay.appleid.com, @private.icloud.com or @icloud.com. iCloud+ subscribers can also create unique, random Hide My Email addresses for any form, and those forward the same way.
Firefox Relay. Mozilla's masks use the mozmail.com domain (older ones used relay.firefox.com). Premium subscribers get their own subdomain and can make up masks on the spot, such as shop@yourdomain.mozmail.com.
SimpleLogin. Run by Proton these days. It offers several shared alias domains, including aleeas.com and simplelogin.co, and paid users can bring their own custom domain, which you cannot list at all.
DuckDuckGo Email Protection. People get a personal Duck Address such as name@duck.com, and can generate private ones such as amaze-gem-spider@duck.com. Each private address can be switched off on its own.
Fastmail Masked Email. A unique, automatically generated address, created at fastmail.com or at a custom domain the person has set up in their Fastmail account.
Proton Pass. Hide-my-email aliases are randomised addresses that forward to the person's Proton inbox, and paid users can create them on their own domains. Proton's help page doesn't list the shared domains, so I've left them out of the code below. The same page calls these "throwaway" addresses, yet by its own description they keep forwarding until the person disables or deletes them.
How they differ from throwaway inboxes
The useful question isn't "does this address hide something?" but "will the person still be able to receive mail here next month?"
- Lifetime. A relay alias lasts until the person turns it off, usually years. A throwaway inbox is gone in minutes or hours.
- Ownership. A relay alias belongs to one account holder, who signed in to create it. A throwaway inbox is often readable by anyone who types the same name.
- Receiving. Mail sent to a relay alias lands in a long-lived personal inbox. Password resets, receipts and account notices work months later.
- Intent. People use aliases precisely because they plan to stay but want to control who can email them, and to switch an address off if it starts getting spam. That is the opposite of someone passing through.
If you block aliases, the people you turn away are the careful ones: those who read privacy settings, pay for iCloud+ or Proton, and use a password manager that offers an alias by default. Sign in with Apple is worse still, because the person may never have typed the address. Apple handed it to you, and rejecting it breaks a login button you offered.
What the CC0 disposable list does
The most widely reused source is the public domain (CC0) disposable-email-domains/disposable-email-domains repository on GitHub. I checked its disposable_email_blocklist.conf on 11 October 2026. It had 9,222 entries, and none of these were among them: privaterelay.appleid.com, private.icloud.com, icloud.com, mozmail.com, relay.firefox.com, aleeas.com, simplelogin.co, duck.com, fastmail.com. mailinator.com is on it, as you would expect.
The repository used to ship an allowlist.conf as well. It was removed on 12 April 2026 (commit 0bccfe3, "remove allowlist and the attached logic"), with the maintainers describing it as an unmaintained list. Just before removal it had 189 entries, including mozmail.com and fastmail.com, but not the Apple, SimpleLogin or DuckDuckGo domains above. So if your code still fetches allowlist.conf, it now gets a 404, and you need your own.
Two more things worth knowing. The blocklist does contain lookalike domains such as domozmail.com and duck2.club, so a substring match on mozmail.com or duck would treat a listed throwaway domain as a relay, or the other way round. And other lists, especially older or hand-maintained ones, do include relay domains. Check whatever list you use before trusting it.
Practical guidance
- Keep a small relay allowlist of your own and check it before the blocklist.
- Match on the exact domain or a dot-separated suffix (
janedoe.mozmail.comends with.mozmail.com), never by substring. - Treat custom domains as ordinary domains. You can't tell a SimpleLogin custom domain from a small business, and you don't need to.
- If you need to recognise the same person across sign-ins, key it on the provider's user ID (Apple's
subclaim), not on the email string. - Apple's relay only forwards mail from sending addresses or domains you have registered for Sign in with Apple. Register yours, or your emails to those users will not arrive.
- Add the shared domains of any other alias service you see in your own signup data, after checking the provider's documentation.
In Laravel, a rule:
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Str;
class NotThrowawayEmail implements ValidationRule
{
private const RELAYS = [
'privaterelay.appleid.com', 'private.icloud.com', 'icloud.com',
'mozmail.com', 'relay.firefox.com', 'duck.com',
'aleeas.com', 'simplelogin.co', 'fastmail.com',
];
public function __construct(private array $blocklist) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$domain = Str::lower(Str::afterLast((string) $value, '@'));
if (self::matches($domain, self::RELAYS)) {
return; // a privacy alias, keep it
}
if (self::matches($domain, $this->blocklist)) {
$fail('Please use an address you will still have next month.');
}
}
private static function matches(string $domain, array $list): bool
{
foreach ($list as $entry) {
if ($domain === $entry || str_ends_with($domain, '.' . $entry)) {
return true;
}
}
return false;
}
}
Load the blocklist once (from a cached copy of the CC0 file) and bind it in a service provider, then use ['required', 'email:rfc', app(NotThrowawayEmail::class)].
In Node the same idea:
const RELAYS = new Set([
"privaterelay.appleid.com", "private.icloud.com", "icloud.com",
"mozmail.com", "relay.firefox.com", "duck.com",
"aleeas.com", "simplelogin.co", "fastmail.com",
]);
function inList(domain, set) {
const parts = domain.split(".");
for (let i = 0; i < parts.length - 1; i++) {
if (set.has(parts.slice(i).join("."))) return true;
}
return false;
}
export function classifyEmailDomain(email, blocklist) {
const domain = email.slice(email.lastIndexOf("@") + 1).toLowerCase();
if (inList(domain, RELAYS)) return "relay";
if (inList(domain, blocklist)) return "throwaway";
return "ordinary";
}
Review the relay list every few months. Providers add domains, and the cost of a stale entry is a careful person seeing an error.
I built Orisift, which flags domains on known throwaway lists. Relay services aren't something it calls out separately, so I keep a relay allowlist like the one above in front of it. The docs are here: https://orisift.com/x?m=post&c=hashnode-privacy-aliases&to=%2Fdocs
