← Back to Insights

Subscriber Key: why an unsubscribed customer keeps receiving your emails

Pierre Frin September 2026 7 min read
une seule personne lea.martin@example.com cliente depuis 2021 SubscriberKey = CLI-88421 statut : désabonnée SubscriberKey = lea.martin@… statut : active envoi parti Marketing Cloud Engagement · All Subscribers

A customer unsubscribes, gets the confirmation, and finds the newsletter back in her inbox the following week. Nobody touched the settings, the unsubscribe link works in testing, and yet the complaint lands on the service desk with the letters GDPR in it.

In Marketing Cloud Engagement, that scenario is almost never a bug. It follows from the data model, and from one value in particular: the Subscriber Key.

Two keys, two people

The Subscriber Key identifies a subscriber. Two rows carrying the same email address under two different keys are, as far as the platform is concerned, two separate people. Everything else follows from that.

TopicBehaviourConsequence with two keys
SendingDuplicates are dropped from a send on the basis of the keyThe same email twice in the same inbox
UnsubscribeThe link acts on the subscriber identified by their keyThe person stays active under the other key
StatusEach subscriber carries its own statusAn address in error stays active elsewhere
ContactsEach key creates a contact, and contacts count towards your contractThe same person is billed twice

Where the duplicate keys come from

The cause is nearly always the same: a sending data extension related to subscribers on the email address, because the source file carried no customer identifier. A loyalty import, a list from a supplier, an export from an events site, and the database splits in two without a single error message.

⚠️ The signal to watch: a complaint about an unsubscribe that was not honoured is rarely an isolated case. If one exists, there are often thousands, and each one is a GDPR breach.

Measuring it, in two queries

The system data view _Subscribers exposes All Subscribers in SQL. First query, the volume: how many addresses exist under more than one key.

SELECT
    s.EmailAddress,
    COUNT(*)          AS NbCles,
    MIN(s.DateJoined) AS PremiereInscription
FROM _Subscribers AS s
WHERE s.EmailAddress IS NOT NULL
GROUP BY s.EmailAddress
HAVING COUNT(*) > 1

A few dozen rows is a clean-up job. Several thousand points to a feed that is wired badly and keeps producing duplicates on every run.

Finding actives unsubscribed under another key

Second query, the cases at risk: subscribers still active while the same address is unsubscribed under another key. Those are the ones that trigger complaints.

SELECT
    actif.SubscriberKey,
    actif.EmailAddress,
    MAX(desab.DateUnsubscribed) AS DateDesabonnement
FROM _Subscribers AS actif
INNER JOIN _Subscribers AS desab
    ON  desab.EmailAddress  = actif.EmailAddress
    AND desab.SubscriberKey <> actif.SubscriberKey
WHERE actif.Status = 'active'
  AND desab.Status = 'unsubscribed'
GROUP BY actif.SubscriberKey, actif.EmailAddress

The GROUP BY stops the same active key being written twice when the address was unsubscribed under several other keys, which would make the write fail in a data extension whose SubscriberKey is the primary key.

💡 Business units: _Subscribers holds enterprise level data. From a child business unit, query ENT._Subscribers to get the full list.

Block first, fix afterwards

The underlying fix takes weeks. In the meantime, an exclusion script stops sends to those addresses. It is an AMPscript expression evaluated for every recipient at send time: if it returns true, the recipient is dropped.

RowCount(LookupRows("Desabonnes_Autre_Cle", "EmailAddress", emailaddr)) > 0

What the exclusion script covers

The test runs on the address rather than the key, so it covers every duplicate at once. LookupRows ignores case, which stops an address typed in capitals from slipping through. Salesforce does warn that a complex exclusion script, or one applied to a large table, slows the send down: on high volumes, filter the audience before it enters the journey.

Fix it at the source

As long as the feed relates on the email address, the duplicates come back. Three steps, in this order:

  1. enrich the source file with the customer identifier, or find it with a matching query before the send;
  2. relate the sending data extension to subscribers on that field, never on the address;
  3. apply the unsubscribe to every key sharing an address, then remove the duplicate contacts with the contact delete process.

⚠️ Do not clean up by deleting rows in All Subscribers: deleting a subscriber also erases its status. If the person comes back through an import, they are active again, and the contact keeps counting until it is deleted in Contact Builder.

Choosing the right key from the start

Salesforce advises against the email address as a Subscriber Key. A good key is unique, stable over time, independent of the channel and shared with your other systems. In practice that is the customer identifier from your master system, or the Contact or Lead identifier when Marketing Cloud Connect is in place. The Contact Key must carry the same value.

Changing the Subscriber Key later

Changing the key later is not a maintenance task: Salesforce states that a migration is planned with your account executive and can freeze sends and imports for several days. Better to choose correctly before the first load.

If you are coming from Adobe Campaign

In Adobe Campaign, the technical key of a recipient is generated by the database, and reconciliation uses the keys you pick at each import. In Marketing Cloud, the Subscriber Key plays both parts at once: you supply it, and it is not easily corrected.

The unsubscribe mechanism will feel familiar. A blacklist flag set on one recipient record does not protect a second record carrying the same address. The difference lies in deduplication, which Campaign can apply on the address while preparing a delivery, whereas Marketing Cloud relies on the key.

The habit worth keeping

Before hunting for a bug in a journey or in an unsubscribe link, run the first query. If NbCles goes above 1 across thousands of addresses, the problem is not in the send: it is in the data model, and no interface setting will fix it.

Frequently asked questions

Why does an unsubscribed person keep receiving your emails?

Two rows carrying the same email address under two different keys are, as far as the platform is concerned, two separate people. The unsubscribe link acts on the subscriber identified by their key, so the person stays active under the other key. That scenario is almost never a bug, it follows from the data model.

How do you measure duplicate addresses in SQL?

The system data view _Subscribers exposes All Subscribers in SQL: a GROUP BY on EmailAddress with HAVING COUNT(*) > 1 gives the number of addresses existing under more than one key. A few dozen rows is a clean-up job, several thousand points to a badly wired feed that keeps producing duplicates on every run. From a child business unit, query ENT._Subscribers to get the full list.

How do you block the sends while the real fix is under way?

An exclusion script, an AMPscript expression evaluated for every recipient at send time, drops the recipient when it returns true. The test runs on the address rather than the key, so it covers every duplicate at once, and LookupRows ignores case. Salesforce does warn that a complex exclusion script, or one applied to a large table, slows the send down: on high volumes, filter the audience before it enters the journey.

Can you clean up by deleting rows in All Subscribers?

No. Deleting a subscriber also erases its status: if the person comes back through an import, they are active again. The contact itself keeps counting until it is deleted in Contact Builder, through the contact delete process.

Which value should you choose as the Subscriber Key?

Salesforce advises against the email address. A good key is unique, stable over time, independent of the channel and shared with your other systems: in practice the customer identifier from your master system, or the Contact or Lead identifier when Marketing Cloud Connect is in place, with the Contact Key carrying the same value. Changing the key later is not a maintenance task: the migration is planned with your account executive and can freeze sends and imports for several days.

More in this series
Pierre Frin
Grokium founder · CRM consultant · Adobe Campaign Classic and Salesforce Marketing Cloud Email Specialist certified

Unsure about your Marketing Cloud data model?

I can review your duplicates, your exclusions and your sends, then hand you a written diagnosis with the queries to run on your own data.

Tell me about your situation →