Things I've learned playing around with Apple Hide My Email
Apple’s Hide My Email feature is pretty useful when you need to hide your real email address when signing up for services. It works by creating alias emails which forward incoming emails to a real email address. An email alias can then be disabled or deleted at the user’s convenience, and service providers no longer have a means to reach the user. This is not exactly something new as Outlook users were able to create email aliases for years. However creating email aliases in Outlook was an arguably tedious manual process and could only be done via the web app. On the other hand, Apple managed to deliver this functionality in a user-friendly way.
I’ve been using Hide My Email for a while and took interest in how it works in the background. Here are some of the things I’ve learned, assumed and deduced with close to zero prior knowledge or research. I do not take responsibility for the accuracy of these observations.
Sending an email to an alias address
Looking at the email headers for an email delivered to a real address via an alias address, we can make a couple of observations.
The To:
header retains the alias address whereas the Delivered-To:
header contains the real address.
Delivered-To: [email protected]
To: Hide My Email <[email protected]>
Most likely how Hide My Email works is that Apple is rewriting the Envelope From address during the SMTP transaction. This is achieved through the milter functionality in Postfix acting on the RCPT TO command. It is safe to assume Apple uses Postfix based on the chain of Received:
headers.
Received: from st43p00im-zteg10061901.me.com (st43p00im-zteg10061901.me.com
[17.58.63.168]) by st43p00im-zteg10061901.me.com (Postfix) with ESMTPS id 99C6B54074E
for <[email protected]>; Fri, 25 Nov 2022 09:38:45 +0000 (UTC)
Received: from st11p00im-smtpin027.me.com (st43p00im.dlb-asmtpoutvip.me.com
[10.76.196.233]) by st43p00im-zteg10061901.me.com (Postfix) with ESMTP id 7FA285404A9
for <[email protected]>; Fri, 25 Nov 2022 09:38:45 +0000 (UTC)
Received: from APC01-SG2-obe.outbound.protection.outlook.com
(mail-sgaapc01olkn2091.outbound.protection.outlook.com [40.92.53.91]) by
st11p00im-smtpin027.me.com (Postfix) with ESMTPS id 71546680046 for
<[email protected]>; Fri, 25 Nov 2022 09:38:44 +0000 (UTC)
Notice how once the email enters Apple’s system (*.me.com
) the email address changes from the alias address to the real address. This supports the milter hypothesis.
There is an X-Icloud-Hme:
header containing the alias address, real address, sender address and some other information.
X-Icloud-Hme: [email protected]; d=www.disneyplus.com;
[email protected]; r=to; [email protected]
The p=
and f=
fields respectively contains the alias and real emails while the s=
field contains the sender email. The d=
field seems to contain some information about where the alias is being used. This is a redacted version of a real alias I’ve used with Disney+, but the contents of the d=
field do not match any of the editable fields in the Hide My Email management GUI. For instance, I’ve labeled this alias as disneyplus.com
not www.disneyplus.com
, so this may not be directly related to user input and may instead be some internally managed field. It so far does not seem to be used anywhere.
The only place the original sender address appears (other than Received:
and DMARC/ARC related headers) is in the X-Icloud-Hme:
header. It is rewriten everywhere else to an iCloud email address.
From: John Doe <sender_at_example_com_(alphanumeric_string1)_(alphanumeric_string2)@icloud.com>
This is again most likely done through a Postfix milter that operates on the DATA command. We will see later why this sender address rewriting is necessary.
In the rewritten sender address, the original sender address is normalized so that it can fit into the local-part of the final iCloud address. The original local-part is kept as-is. The @
sign is converted to _at_
and dots in the domain-part are converted to underscores.
Next is an alphanumeric string, which upon experimenting with sending some emails we can observe that it is unique to the alias email address. All emails sent to the same alias email address have the same value. I’ve therefore chosen to name this first alphanumeric string the alias_lookup_key
, as it is my guess that it may be used to perform some sort of lookup to link the alias email address to its forwarding email address.
I’ve chosen to call the second alphanumeric string the secret_string
as that is what Apple refers it to in error messages. For now I’ll just stick to defining those strings as I’ll go into more details below.
rewritten sender address = <normalized sender address>_<alias_lookup_key>_<secret_string>@icloud.com
On an unrelated note, we can also see from the email headers that Apple uses Rspamd in their email infrastructure, minimally for generating DKIM signatures. This is not relevant to the Hide My Email feature however.
For now that’s all the interesting observation we can make on the headers of an email received via Hide My Email.
Responding to an email sent to an alias address
Hide My Email also supports replies. The real email address is also hidden when replying to an email sent via Hide My Email. When looking at the headers of a delivered response email, we can make a few more observations.
The X-Icloud-Hme:
header has been removed. This is good since that header contains the real email address and is not a header we would want exposed to senders.
The From:
and To:
headers are set respectively to the alias email address and the email address of the sender being replied to.
to: [email protected]
from: [email protected]
These were again likely to have been rewritten by a Postfix milter operating on the DATA command.
The original sender email address is reconstructed when the reply email transits the first SMTP server in Apple’s infrastructure. This can be observed through the chain of Received:
headers.
Received: from ms11p00im-qufv17081501.me.com (ms11p00im-dlb-asmtpoutvip.me.com [10.52.196.131])
by ms11p00im-hyfv17281201.me.com (Postfix) with ESMTP id C896BC806F0
for <[email protected]>; Wed, 23 Nov 2022 04:55:40 +0000 (UTC)
Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131])
by ms11p00im-qufv17081501.me.com (Postfix) with ESMTPS id D8F4736BDAA5
for <[email protected]>; Wed, 23 Nov 2022 04:55:39 +0000 (UTC)
And that’s pretty all we can see. The use of a rewritten sender email address is necessary so that replies to emails sent through Hide My Email are first routed through Apple’s infrastructure. Otherwise, replying to an email would expose the real email address.
I’ve performed a few experiments replying from the real email address to better understand the structure of the rewritten sender address.
Sending a reply from another real email address
My email provider also supports using different aliases for the same mailbox account and selecting which email address to use when replying to an email. So what happens if I reply from [email protected]
?
The email gets rejected by Apple’s SMTP server with the following permanent failure message:
host mx02.mail.icloud.com[17.57.155.34] said: 550 5.7.1 Delivery not authorized (in reply to end of DATA command)
It seems that Apple requires that replies are sent from the forwarded address.
Now what if I go to my Settings and change the forwarding email address for my iCloud account? The email gets delivered successfully. This leads me to believe that the alias_lookup_key
is used to lookup the alias email address and retrieve the forwarding address. If the lookup fails, the email is rejected.
Sending an email to an arbitrary email address
We’ve seen how the rewritten sender email address looks like:
<normalized sender address>_<alias_lookup_key>_<secret_string>@icloud.com
The secret_string
is still a mystery, but the normalized sender address looks pretty straightforward. So what happens when we normalize an arbitrary email address and use it to send an email from our real email address? We know that thanks to the alias_lookup_key
our real email address should be rewritten accordingly, so if things go well we should be able to send emails to anyone and make it appear to be sent from our alias email address. Since the secret_string
is a mystery, we’ll reuse it.
arbitrary_at_example_com_<alias_lookup_key>_<secret_string>@icloud.com
The email gets rejected by Apple’s SMTP server with the following permanent failure message:
host mx02.mail.icloud.com[17.57.155.34] said: 550 5.1.1 Invalid secret string in to header (in reply to end of DATA command)
This is the reason why I’ve chosen to call that string the secret_string
as this seems to be what Apple refers it to. Based on the error message, we can guess that this string is computed from the sender email address, with perhaps some other unknown inputs, and serves as some sort of checksum. With the current knowledge available to us it is therefore not possible to send emails to arbitrary recipients this way.
Additional observations on the rewritten sender address
The rewritten sender email address is normalized by replacing the @
sign and dots in the domain-part. This is an interesting choice as some information is lost during that normalization. For instance, the following valid albeit very distinct email addresses will normalize to the same address:
- [email protected] -> real.c_at_at_example_com
- [email protected] -> real.c_at_at_example_com
If when sending a reply Apple is reconstructing the original sender email address from the normalized version, this can lead to erroneous conversions. For instance, if they reconstruct the original email address by parsing the normalized address right-to-left until the first _at_
and treat everything to its left as the local-part, the result would be [email protected]
which would be erroneous in the case of [email protected]
. Parsing left-to-right would also make no sense as it can easily go wrong.
Perhaps this is why the secret_string
is needed, as reconstructing the sender email address based entirely on user-provided values is risky and error-prone. This leaves the question of how that secret_string
, which is a hexadecimal string, is used. Apple could have used a lookup table and use that string to lookup the sender address. However this is unlikely as it would not scale well. On the other hand, if they try to reconstitute the original address from the normalized version, comparing every possible reconstructions with the secret_string
, this could be time consuming. For instance, the following sender email address would require several attempts:
Database
At the very least, looking up the forwarding email address from an alias email address and allowing users to create and manage aliases definitely requires some sort of database. Based on the information we have, we can make a rough approximation of how that database would be structured.
Fields like alias activation status and other metadata are being left out, but at the very least to provide the Hide My Email feature the information provided by these two database tables would be necessary. The main profile would house iCloud account data that existed way before the Hide My Email feature was introduced, and is likely to contain the forwarding email address. This allows quick updates of the forwarding email address. A separate table containing alias emails and their current state likely references the iCloud user and has a many-to-one relationship with the main profile table.
With this information in hand, we can see that the Hide My Email feature can be pretty simply implemented. On the backend, all it requires is a clever use of Postfix milters, and anyone familiar with milters could write their own version of Hide My Email. This also showcases how powerful Postfix can be.
Additional observations
While playing around, I’ve made a few more observations for which I did not find a good place to discuss.
First, and kind of obviously, using an email address on a domain you own for a forwarding address is not a good idea. Services like Google Workspace and Protonmail allow you to bring your own domain and send emails from a custom domain. With current email best practices, setting up SPF/DKIM/DMARC on your domain is recommended. However, when using Hide My Email, your custom domain will appear in DMARC related headers in reply emails. This may not expose your real email address, but knowing the domain can already be too much information. Using a generic email address as a forwarding email address would be a safer choice.
Similarly, email replies should not be PGP or S/MIME signed, as the signature will leak your real email address.