How Developers Use Disposable Email for Testing
Testing email functionality is tedious. Create Gmail account #47, verify it, check the inbox, screenshot the email, repeat for every test.
Disposable email changes this: generate address, test flow, close tab. Zero cleanup, zero manual work.
The Testing Problem
Traditional email testing workflow:
1. Create test user with [email protected]
2. Trigger password reset
3. Open Gmail in another tab
4. Wait for email
5. Find it among 200 other test emails
6. Test complete
7. Inbox now has 247 test emails
Problems:
- Pollutes your inbox
- Can't parallelize (same address gets reused)
- Gmail might flag your test emails as spam
- Have to manually clean up hundreds of test accounts
Solution: Disposable Email API
With tempy.email:
// Create mailbox
const mailbox = await fetch('https://tempy.email/api/v1/mailbox', {
method: 'POST'
}).then(r => r.json());
// Use it in your test
await yourApp.signup({ email: mailbox.email });
// Get emails
const emails = await fetch(
`https://tempy.email/api/v1/mailbox/${mailbox.email}/emails`
).then(r => r.json());
console.log(emails[0].subject); // "Verify your email"
// Address expires automatically - zero cleanup
Real Use Cases
1. Integration Testing
def test_welcome_email():
# Generate temp mailbox
r = requests.post('https://tempy.email/api/v1/mailbox')
email = r.json()['email']
# Create user
create_user(email=email)
# Check inbox
time.sleep(2)
emails = requests.get(f'https://tempy.email/api/v1/mailbox/{email}/emails')
assert "Welcome" in emails.json()[0]['subject']
2. E2E Testing (Cypress/Playwright)
// Generate unique email per test run
const mailbox = await cy.request('POST', 'https://tempy.email/api/v1/mailbox');
cy.visit('/signup');
cy.get('[name="email"]').type(mailbox.body.email);
cy.get('button').click();
// Poll for verification email
cy.wait(2000);
cy.request(`https://tempy.email/api/v1/mailbox/${mailbox.body.email}/emails`)
.then((res) => {
const link = extractLink(res.body[0].bodyHtml);
cy.visit(link);
});
3. Load Testing
Test 1000 signups in parallel - each gets unique address:
await Promise.all(
Array(1000).fill().map(async () => {
const m = await createMailbox();
await testSignup(m.email);
// Auto-expires, no cleanup needed
})
);
4. Email Template Verification
// Send test email
await sendEmail({
to: tempAddress,
template: 'order_confirmation',
data: { order: '12345', total: '$99' }
});
// Verify template rendered correctly
const email = await getEmail(tempAddress);
assert(email.bodyHtml.includes('Order #12345'));
assert(email.bodyHtml.includes('$99'));
API Reference
Create mailbox:
POST https://tempy.email/api/v1/mailbox
→ { "email": "[email protected]", "expires_at": "..." }
Get emails:
GET https://tempy.email/api/v1/mailbox/{address}/emails
→ [{ "subject": "...", "bodyHtml": "...", ... }]
Extend TTL:
POST https://tempy.email/api/v1/mailbox/{address}/extend
→ Adds 5 minutes
Best Practices
✅ Use unique addresses per test:
// Each test gets fresh inbox
test('signup', async () => {
const email = await createUniqueEmail();
await testWith(email);
});
✅ Poll for emails:
async function pollForEmail(address, timeout = 10000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const emails = await getEmails(address);
if (emails.length > 0) return emails[0];
await sleep(500);
}
throw new Error('Email not received');
}
❌ Don't use shared addresses:
// Bad - emails from different tests mix
const SHARED_EMAIL = '[email protected]';
Time Savings
Before: 10 min/test × 100 tests/week = 1000 min/week = 16.7 hours/week
After: 30 sec/test × 100 tests = 50 min/week
Saved: 15+ hours per developer per week.
CI/CD Integration
# .github/workflows/test.yml
name: Email Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm test -- email.test.js
env:
TEMP_EMAIL_API: https://tempy.email/api/v1
No API keys. No rate limits. Just works.
Stop polluting your inbox. Start testing smarter with tempy.email.