---
title: "Test that a welcome offer can't be claimed twice · Proxy Mail QA"
description: "Sign up again as name+promo1@ and NAME@, which reach the same inbox, and see whether your app gave the same person its welcome offer twice."
url: https://proxymail.qa/solve/welcome-offer-abuse
---

1. [Home](https://proxymail.qa/)
2. [What we solve](https://proxymail.qa/solve)

# Test that one person gets one welcome offer

Most email providers deliver name+anything@ and NAME@ to the same inbox, so to many apps one person looks like several new customers, each with a welcome discount. Sign up with each version and see whether your app noticed.

Updated 21 October 2026

## The versions to try

| Version  | Example                    | Reaches        |
| -------- | -------------------------- | -------------- |
| Plain    | k3f9x2@mailclub.dev        | The inbox      |
| Plus-tag | k3f9x2+promo1@mailclub.dev | The same inbox |
| Capitals | K3F9X2@mailclub.dev        | The same inbox |

Any +tag works, and the inbox shows which version each email went to. Agents get the versions that deliver from `get_address_variants`.

## Test it

1. **Sign up for the offer** with the plain address and note the coupon.
2. **Sign up again** with the plus-tag version, then with capitals, in a private window each time so no session carries over.
3. **Look at the inbox.** Each email shows which version it went to. If a second coupon came, its `offer_reuse` check fails and the Accounts page warns that the welcome offer went out more than once.

The check also says whether the coupons differ (the app issued a new one each time) or are the same shared code, where it’s up to checkout to refuse a second use. Record what checkout did with [coupon results](https://proxymail.qa/solve/coupon-code-testing): a coupon accepted for a reused offer fails.

## In a test

offer-reuse.spec.ts

```ts
const tagged = address.replace('@', '+promo1@');
let submitted = new Date();
await signUpForOffer(page, address);
await qa.waitForCode(address, { type: 'coupon', since: submitted, timeout: 600 });

submitted = new Date();
await signUpForOffer(page, tagged);
// The same person: no second coupon should come.
await qa.expectNoEmail(tagged, { since: submitted, type: 'code', subtype: 'coupon', timeout: 300 });
expect((await qa.offers(address)).passed).toBe(true);

```

Agents get the same with `get_address_variants`, `wait_for_code` (kind `coupon`) and `check_offers`, and the `test_offer_reuse` prompt walks through it.

## Automating this?

Make it a test: sign up with the plain address and a +tag version, wait for the first coupon, then expectNoEmail on the tagged one with type code and subtype coupon. offers(address) says whether any offer went to two versions.

[Node.js client](https://proxymail.qa/docs/node) [Python](https://proxymail.qa/docs/python) [Set up your coding agent](https://proxymail.qa/docs/api#agent-setup)

## Try it on your next sign-up test

Free plan, no credit card. Create an address and watch the code or link arrive.

[Create a free account](https://app.proxymail.qa/?mode=signup&from=site-solve-welcome-offer-abuse)

## Questions

### Do I need to switch anything on?

Yes, for now. Marketing and offer emails is in Labs: switch it on in the app under **Account settings → Labs**. It applies to your API keys and agents too; until then their marketing tools answer with an error that says so.

### Do these versions really reach the same inbox?

Yes. Mail to name+promo1@ and NAME@ arrives at name@, as it does at Gmail, Outlook and most providers, so the test matches what real people can do.

### What about Gmail's dots, like n.a.m.e@gmail.com?

Proxy Mail QA can't test those: on our domains, a dot makes a different address. If your app normalises Gmail addresses, test that rule with unit tests.

### Should my app block +tags altogether?

Usually not: many people use them to sort mail. A common fix is to normalise the address when checking whether someone has had the offer, and keep the address they typed for sending.

## Related guides

- [Test sign-up and email verificationA fresh, private address for every sign-up test, with the verification link or code ready the moment it lands.](https://proxymail.qa/solve/email-verification-testing)
- [Test OTP and one-time login codesCodes pulled out of the email with a Copy button and a countdown when the email says how long they last.](https://proxymail.qa/solve/otp-code-testing)
- [Test magic links and passwordless sign-inSingle-use links that are never opened or prefetched on our side, so they still work when you click them.](https://proxymail.qa/solve/magic-link-testing)
- [Test password reset emailsRequest, receive and use reset links, and keep the new password saved next to the test account.](https://proxymail.qa/solve/password-reset-testing)
- [Stop sharing one Gmail inbox for QAPrivate, disposable addresses for every tester instead of one shared mailbox and a pile of plus-addresses.](https://proxymail.qa/solve/shared-test-inbox)
- [Take QA notes by voice with Wispr FlowDictate what each test account is for, its state and what you found, straight into its notes, in seconds.](https://proxymail.qa/solve/voice-notes-wispr-flow)
- [Verification link points to localhost:3000Why emails from staging link to localhost, how to fix it in Supabase, Firebase and other stacks, and how we flag it.](https://proxymail.qa/solve/localhost-links)
- [Common Supabase sign-up and login problemsEmails that never arrive, links that expire or sign nobody in, and sign-ups that fail, with the fix for each.](https://proxymail.qa/solve/supabase-auth-problems)
- [Common Firebase sign-up and login problemsMissing verification and reset emails, verified users who still look unverified, failing links and sign-up limits, with the fix for each.](https://proxymail.qa/solve/firebase-auth-problems)
- [Sign-up and login problems in vibe-coded appsThe login bugs AI-built apps usually ship with: emails only you receive, links to the preview, missing pages, and what to ask the builder.](https://proxymail.qa/solve/vibe-coded-login-problems)
- [Test sign-up emails in PlaywrightA complete Playwright test for sign-up codes and links, from a fresh inbox to the report on the pull request.](https://proxymail.qa/solve/playwright-email-tests)
- [Test sign-up emails in CypressA complete Cypress test for sign-up links and codes, with the email waits running as Cypress tasks.](https://proxymail.qa/solve/cypress-email-tests)
- [Test sign-up emails with pytestA complete pytest test for sign-up codes and links, with Playwright for Python or Selenium and a one-file helper.](https://proxymail.qa/solve/pytest-email-tests)
- [Test coupon codes and welcome offersThe coupon with its discount, end date and arrival time, what checkout did with it, and a failure when an expired or reused one is accepted.](https://proxymail.qa/solve/coupon-code-testing)
- [Test unsubscribe links and one-click unsubscribeThe unsubscribe headers and link checked on every marketing email, and a watch that flags any marketing after unsubscribing, with no time limit.](https://proxymail.qa/solve/unsubscribe-testing)

[Built your app with an AI tool? Pick yours](https://proxymail.qa/built-with)
