The same customer appears as an email address, a user id, and a Stripe customer. Merge them badly and you send three copies of the same onboarding email; merge them lazily and you cannot answer 'who is this'.
Pick the strongest key and never change it
The email address is the natural key for email, but it is mutable: people change addresses and teams reassign aliases. The durable key is your internal contact id. Everything else — email, external ids, phone — is an attribute that can be added or retired without breaking history.
Keep an identity table, not a wide row
One table of (contact_id, kind, value, verified_at) lets one contact hold two email addresses, an external CRM id, and a phone number without schema changes. Looking up which contact owns an address becomes a single indexed query, which is the only thing the send path actually needs.
Decide what a merge does to history
If two contacts are merged, their events should not be silently reattributed. Keep the event's original contact id and add a pointer to the surviving contact. Otherwise a merge rewrites analytics and any number you reported last month changes retroactively.
The detail that prevents duplicate sends
Deduplicate at the point of enqueue with a key composed of (contact_id, template_id, dedupe_window). Two features firing the same welcome email within five minutes then produce one message, and the rule lives in one place instead of in every caller.
Volanea keys contacts by id with verified identities attached, so a second address for the same person does not create a second contact.

