Free trial abuse: the email signals that catch it, and where they stop

Stop repeat free-trial sign-ups with email signals: disposable and relay inboxes, +tag and Gmail-dot variants, typo domains, new domains and a blocklist.

  • #fraud
  • #signup
  • #disposable-email
  • #policy
Five sign-ups, including jane+1@gmail.com, j.ane@gmail.com, a temp-inbox.example address, a relay and a 2-day-old domain, each marked block or review and grouped into one badge reading 1 person. // 5 trial sign-ups jane+1@gmail.com +tag on jane@gmail.com review j.ane@gmail.com Gmail ignores the dot review x7@temp-inbox.example disposable inbox block k2@privaterelay.appleid.com relay alias block jane@acme-trial.io domain registered 2 days ago review 1 person one trial // block what's certain, review the rest

Free trial abuse is one person starting your trial again and again under a new email address each time. The address is where most of it shows first: throwaway inboxes, privacy relays, +tag and Gmail-dot variants of the same inbox, typo and lookalike domains, and company-looking domains registered last week. Block only what you’re sure of, de-duplicate the rest, and send uncertain sign-ups to a review lane, because every false positive is a real customer you turned away.

Why abuse starts with the email address

If your trial includes something that costs you money, such as AI credits, compute, SMS, seats or data exports, a new trial is worth a new identity. The cheapest new identity is a new email address, and there are several ways to get one, each a little more expensive than the last:

Trick Effort for the abuser Example
+tag on the same inbox None jane+2@gmail.com
Dots in a Gmail address None j.ane@gmail.com
Disposable inbox Seconds x7@temp-inbox.example
Relay alias Seconds, with an account k2@privaterelay.appleid.com
New webmail account Minutes, sometimes a phone number jane.trial7@outlook.com
New domain with a catch-all A few dollars jane@acme-trial.io

The goal isn’t to make abuse impossible. It’s to make each extra trial cost more than it’s worth, while a genuine sign-up costs nothing extra. The free trial abuse playbook has the short version; this post goes through each signal, what it catches and where it stops.

The signals, one by one

Disposable inboxes: always block

Throwaway inbox services hand out working addresses in seconds and forget them within hours. isBusinessEmail returns category: "disposable" and is_disposable: true, with a reason that says how it knew: disposable_provider for a list match, mx_shared_disposable when the domain’s mail servers also serve known disposable domains, or disposable_name when the name advertises it and nothing suggests a real organization. Every policy blocks them.

This is the one signal to block without a second thought. A disposable inbox won’t receive your onboarding email next week, so even a genuine person behind it isn’t someone you can reach. Why lists alone miss some of them is in the disposable email problem, and the disposable email checker checks a single domain.

Relays: block for B2B, decide for consumer products

Apple Hide My Email, Firefox Relay, DuckDuckGo, SimpleLogin and addy.io forward to a real, persistent inbox. The person is reachable, so a relay isn’t disposable. But one account can create many aliases, so you can’t de-duplicate by address, and the alias hides which company the person works for. is_relay is true; the b2b and strict policies block, lenient allows.

For a B2B trial, blocking relays is reasonable. On a consumer product, privacy-minded people use them on purpose, and Sign in with Apple can hand them out by design. Allow them there, with limits, and lean on the controls further down. Email relay addresses covers the trade-off.

Personal providers: a policy choice, not an abuse signal

A gmail.com address isn’t abuse. Most consumers and many buyers sign up that way. is_free_provider tells you the domain is shared; what you do about it is a product decision. If your product needs a company account, require a work email, as should B2B SaaS block free email signups? discusses. If it doesn’t, allow personal addresses and de-duplicate them properly.

Requiring a work email has a side effect worth planning for: it pushes abusers toward cheap new domains, which is why the domain-age signal below matters more once you do.

+tags and Gmail dots: one inbox, many addresses

jane+1@gmail.com, jane+trial@gmail.com and jane@gmail.com all land in the same inbox. isBusinessEmail flags the tag with has_subaddress and the reason subaddress, and returns normalized_email without it: jane@gmail.com.

Gmail also ignores dots in the name, so j.ane@gmail.com and ja.ne@googlemail.com reach that inbox too. normalized_email removes +tags but doesn’t fold dots, because that rule belongs to one provider. Fold them yourself, and only for gmail.com and googlemail.com: Google Workspace on a company domain and most other providers treat j.ane and jane as different people.

const GMAIL = new Set(['gmail.com', 'googlemail.com']);

// One key per inbox: the API already dropped the +tag; fold Gmail dots here.
function trialKey(v) {
  if (!v.normalized_email) return null;
  const at = v.normalized_email.lastIndexOf('@');
  const local = v.normalized_email.slice(0, at);
  const domain = v.normalized_email.slice(at + 1);
  return GMAIL.has(domain) ? `${local.replaceAll('.', '')}@gmail.com` : v.normalized_email;
}

Store the key in its own column with a unique index, and allow one trial per key. Don’t reject +tags themselves: many careful people use them to filter mail, and a tag only matters when the address without it already has a trial. Plus addressing and sign-up dedupe goes deeper.

Typo and lookalike domains

jane@gmial.com is usually an honest mistake. did_you_mean returns gmail.com with the reason typo_suspected; show it as a one-click fix and check again, as email typo domains describes. Some typo domains are themselves run as throwaway inbox services; those come back disposable with did_you_mean still filled.

Lookalikes are more often deliberate: a Cyrillic о in place of a Latin o, or a 0 for an o. is_lookalike is true with the reason lookalike_domain, and under b2b such an address never gets a plain allow. Detection compares the domain with popular email providers, not with your brand, so check imitations of your own domain yourself. See lookalike and punycode domains.

Brand-new domains

Once personal and disposable addresses are out, the cheapest workaround is a domain: acme-trial.io for a few dollars, plus a catch-all so every address on it works. With deep=true, isBusinessEmail looks up the registration date over RDAP and checks the homepage, returning domain_age_days, is_new_domain (under 30 days) and reasons such as new_domain, young_domain and parked_domain. A deep check counts as 5 checks, with at most 1,000 a day, so run it at trial start and only for custom domains.

New isn’t proof: real startups sign up the week they register. Review new domains rather than blocking them, and watch for several trials from the same new domain, which is one organization whatever comes before the @. Domain age as a fraud signal covers this in detail.

The blocklist

is_blocked is true when the domain, or for secret keys the exact address, is on the isBusinessEmail blocklist, which our admins maintain after reviewing spam and abuse reports. The reasons are blocked_domain and blocked_email, and every policy blocks. Exact addresses are stored only as hashes. If abuse keeps coming from a domain that should be listed, report it.

Unknown

category: "unknown" means a custom domain with too little evidence to call: very new, parked, no SPF or DMARC, forwarding-only mail, or a name that suggests a mailbox service. b2b returns review, strict blocks and lenient allows (categories and policies). For trials, treat it as review.

What email signals can’t catch

Email checks stop the cheap, repeatable abuse. They don’t stop someone with an established company domain or a stack of genuine webmail accounts, because every one of those addresses is real. isBusinessEmail also never checks whether a mailbox exists, so send a confirmation email before the trial starts; it proves the inbox works, though a disposable inbox passes it too.

Pair the email check with controls that don’t depend on the address:

  • Rate limits on sign-ups per IP address, device and network, and on the expensive actions themselves.
  • Card verification before the costly part of the trial, with a check that the same card hasn’t already started one.
  • Usage caps per trial on credits, exports, messages or seats, so the worst case of one abusive trial stays small.
  • Behavior after sign-up, such as several new accounts with the same onboarding answers or the same usage pattern.

A policy: signal to action

Signal Field Action
On the blocklist is_blocked block
Typo of a provider did_you_mean ask to confirm the fix, then check again
Disposable inbox is_disposable block
Can’t receive mail category: "invalid" block, with a “check for typos” message
Same inbox as an existing trial your trial key no second trial; offer to sign in
Relay is_relay block for B2B; allow with limits for consumer products
Lookalike of a provider is_lookalike review
New domain (under 30 days) is_new_domain review: card or manual approval
Parked homepage reason parked_domain review
Unknown category: "unknown" review
Personal provider is_free_provider your policy: allow with limits, or block on work-email products
+tag on a first trial has_subaddress allow
Established business domain category: "business" allow

Review should mean “let them in, hold back the expensive part”: a confirmed email, a card on file, a quick manual look, or a few days of normal usage. Most reviewed sign-ups are genuine, so keep the step light.

Putting it together in code

check() below is a thin wrapper around POST /v1/check with a timeout that returns null on any failure; the code examples have one in several languages. The typo check comes before the disposable and invalid blocks on purpose: someone who typed gmial.com should see the fix, not a rejection.

async function screenTrial(email, { b2b }) {
  let v = await check(email);
  if (!v) return { lane: 'allow', recheck: true }; // fail open, re-check later
  if (['business', 'unknown'].includes(v.category)) v = (await check(email, { deep: true })) ?? v;

  if (v.is_blocked) return { lane: 'block' };
  if (v.did_you_mean) return { lane: 'confirm', suggestion: v.did_you_mean };
  if (v.is_disposable || v.category === 'invalid') return { lane: 'block' };

  const key = trialKey(v);
  if (key && (await trials.exists(key))) return { lane: 'existing_account' };

  const codes = v.reasons.map((r) => r.split(':')[0]);
  if (v.is_lookalike || v.is_new_domain || v.category === 'unknown' || codes.includes('parked_domain')) {
    return { lane: 'review', key };
  }
  if (v.is_relay || v.is_free_provider) return { lane: b2b ? 'block' : 'limited', key };
  return { lane: 'allow', key };
}

Store the lane and reasons on every trial. After a few weeks, count how many reviewed sign-ups you approved and how each lane converted to paid. If nearly every reviewed account turns out fine, the lane is too wide; narrow one rule at a time.

Next steps

  1. Block disposable and blocklisted addresses first; each is a single field.
  2. Add the trial key with Gmail dot folding and a unique index.
  3. Route relays, lookalikes, unknown and new domains to review, and cap what a trial can use.
  4. Test every lane with the test addresses, such as disposable@test.isbusinessemail.com and unknown@test.isbusinessemail.com, then get a free API key.

Frequently asked questions

How do I stop people from signing up for multiple free trials?

Build a key for every trial from the email address with +tags removed and, for gmail.com and googlemail.com only, dots removed, and allow one trial per key. Block disposable inboxes, review relays and brand-new domains, and add rate limits, card checks and usage caps for the expensive features.

Should I block Gmail addresses to stop trial abuse?

Usually not. Most people who sign up with Gmail are genuine, and blocking them costs you real customers. De-duplicate Gmail addresses properly and cap what a trial can use instead. Require a work email only if your product needs a company account anyway.

Does Gmail really ignore dots in addresses?

Yes. For gmail.com and googlemail.com, j.ane@gmail.com and jane@gmail.com reach the same inbox. Google Workspace accounts on a company domain and most other providers treat dots as part of the name, so fold dots only for those two domains.

Are plus addresses a sign of fraud?

No. Many careful people use a +tag to filter mail by sender. A tag only matters when the same address without it already has a trial, so de-duplicate on the normalized address instead of rejecting tags.

Can email checks stop all free trial abuse?

No. Someone with an established company domain or a stack of genuine webmail accounts passes any email check, because every one of those addresses is real. Email signals stop the cheap, repeatable abuse; rate limits, card verification and usage caps handle the rest.

What should happen to sign-ups that land in review?

Let them start, but hold back what is expensive until something confirms they are real: a confirmed email, a card on file, a quick manual approval or a few days of normal usage. Most reviewed sign-ups are genuine, so keep the step light.