What Google actually shipped
Rollout started late 2025 and has kept expanding through 2026. Change your address in your Google Account email settings and the account survives intact: messages, Drive, subscriptions.
The old address stays as an alias and keeps receiving. Google even publishes a troubleshooting doc for the fallout, which tells you they know the ecosystem is not ready.
Coverage of the launch lives in 9to5Google and CNET.
For consumers this is overdue polish. For builders it is a schema event, because three assumptions almost every app embeds just broke:
- Email identifies a person
- Email is stable enough to key rows and joins on
- A verified email stays verified
Where Twynon got it right, mostly by accident
The accounts table is merchants. The primary key was never the email:
create table if not exists merchants (
merchant_id uuid primary key,
email text unique not null,
password_hash text,
auth_provider text,
google_sub text,
...
);
And the service mints it as a random UUID:
merchant_id = uuid.uuid4()
The whole reverse-marketplace pipeline then references ids, never strings.
A buyer's "wanted" request, the merchant responses it creates and their chat rows chain like this:
create table looking_requests (
request_id uuid primary key,
seeker_id uuid not null, ...
);
create table leads (
lead_id uuid primary key,
request_id uuid not null,
merchant_id uuid not null, ...
);
create table lead_messages (
message_id uuid primary key,
lead_id uuid not null,
sender_id uuid not null, ...
);
So when a merchant's Gmail address changes mid-negotiation, the conversation does not rot. The buyer, the merchant and every message still resolve to the same accounts.
Where Twynon got it wrong, on purpose
This is the honest part. Three cracks are already in the design.
1. Email is still a login key
email text unique not null plus password auth means the address is the credential. If a user changes their Gmail and signs up again with the new address, Twynon happily creates a second account. Same human, two seller accounts, two balances, zero fraud flags. The uniqueness constraint protects the wrong invariant: it guarantees two people cannot share an address, when what matters is one person not owning two accounts.
2. Google linking trusts email as a fallback
Sign-in with Google is the good news here. Google hands every sign-in a permanent, private account id, which Twynon stores as google_sub. That id never changes, even when the address does. The linking code checks it first:
merchant = get_merchant_by_google_sub(google_sub)
if merchant:
return merchant, False # stable identity, email irrelevant
by_email = get_merchant_by_email(email)
if by_email:
# link the sub to the existing email account
The fallback is the problem. An account that signed up with a password and never connected its Google id gets stitched to a Google login by email match. The moment emails become mutable, that stitching turns into a race: the user changes address, someone else claims the old one later, and "verified by email" becomes a claim about a mailbox that no longer belongs to your user. Email match should be a hint the user confirms with a one-time code, never an automatic account merge.
3. Verification is one-shot
is_verified flips to true once a one-time code passes at signup. WhatsApp verification works the same way. Both prove only that you controlled the address the day you signed up. Neither says the account is still reachable at the address we stored. Under mutable emails the stored address goes stale silently and the verified badge starts lying.
The model that survives mutable email
The direction Twynon is adopting: a person signs up with their old email, adds a new one later, and either address reaches the same account. Work in progress.
- Email moves from column to attribute table:
create table account_emails (
email_id uuid primary key default gen_random_uuid(),
merchant_id uuid not null references merchants(merchant_id),
address text not null unique,
is_primary boolean not null default false,
verified_at timestamp,
created_at timestamp default current_timestamp
);
-
addressis a lookup, never the key. Identity lives inmerchant_id, plus the Google or Apple sign-in id when one is connected. A key that changes when addresses change is the old bug with extra rows. - Adding an address is a verified flow, not a field edit: control of both the new address and an existing one must be proven before the new one can sign in.
- Collisions never auto-merge. If the address belongs to another account, connect from inside that account or request a merge confirmed on both sides. Auto-merge by email match is the race described above.
- Existing addresses are told when a new one joins, and no account can remove its last verified contact path. Silent addition is how takeovers go unnoticed.
-
verified_atmakes stale trust queryable. Re-verify on change. - Notifications go to every live address, so delivery survives while identity moves forward.
- Raw emails appear nowhere a user sees or a row references. The API returns ids and display names.
The one-liner version: email is a mailbox you currently control, not a person. Model the mailbox as the mutable thing it is, and let people own several.
What this means for schema.org markup
The same insight is already in Google's structured data guidance. Email is noted there as a contact channel, and identity is expected elsewhere:
- Since August 2021,
author.urlis Google's recommended way to reliably credit who wrote an article. A URL is stable, an email is not - The December 2023 Organization updatelists
emailandtelephonealongsidecontactPointas reachability properties, not identifying ones - Discussion Forum and Q&A guidance recommends author URLs for people behind posts
So when you publish structured data for user-generated content, Person.name and Person.url carry identity, Person.email is optional plumbing at best.
Publishing author emails in structured data now also publishes a moving target with no upside.
Wrapping up
Email became a mutable attribute of an identity, not the identity itself. If your schema stores it once, keys uniqueness on it and verifies it once, you are holding the old contract with no notice period. Audit the three spots above this week: the unique constraint, the Google link fallback and the one-shot verification flag.
Question for you: where did email-as-identifier last bite you in production, and did anyone catch it before the users did?
Twynon is live at twynon.vercel.app if you want to poke at the identity flows yourself. Building in public, bugs included.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.