# Sending test emails

Lettermint provides special test addresses that simulate real-world delivery scenarios (bounces, complaints, and successful deliveries) without sending actual emails. Use them to verify your integration handles all outcomes correctly.

## Why use test addresses?

:::warning
Sending test emails to real mailboxes (including your own) can harm your sender reputation. Repeated bounces, spam complaints, or test content flagged as suspicious may cause mailbox providers to throttle or block your domain. Test addresses let you simulate every scenario without affecting your deliverability metrics.
:::

Test emails sent to `@testing.lettermint.co` addresses are:

- **Excluded from billing**: They don't count toward your monthly email quota
- **Excluded from statistics**: They won't skew your bounce or complaint rates
- **Processed instantly**: Events are generated within seconds

## Test addresses

Send to any of these addresses to trigger specific delivery events:

| Address | Simulated Event | Webhook Event |
|---------|-----------------|---------------|
| `ok@testing.lettermint.co` | Successful delivery | `message.delivered` |
| `softbounce@testing.lettermint.co` | Soft bounce (mailbox full) | `message.soft_bounced` |
| `hardbounce@testing.lettermint.co` | Hard bounce (user unknown) | `message.hard_bounced` |
| `spamcomplaint@testing.lettermint.co` | Delivery + spam complaint | `message.delivered` → `message.spam_complaint` |
| `dsn@testing.lettermint.co` | Out-of-band DSN bounce | `message.hard_bounced` |

:::info
The local part (before `@`) determines behavior. You can use any local part ending in `@testing.lettermint.co`. For example, `user+tag@testing.lettermint.co` also works.
:::

## Sending test emails

<CodeTabs>

```typescript title="Node.js"
import { Lettermint } from "lettermint";

const email = Lettermint.email(process.env.LETTERMINT_PROJECT_TOKEN!);

// Test a soft bounce scenario
const response = await email
  .from("you@yourdomain.com")
  .to("softbounce@testing.lettermint.co")
  .subject("Test soft bounce")
  .text("This will simulate a soft bounce.")
  .send();

console.log(`Test email queued: ${response.message_id}`);
// Later: webhook fires with message.soft_bounced
```

```php title="PHP"
<?php

$email = Lettermint\Lettermint::email(getenv('LETTERMINT_PROJECT_TOKEN'));

// Test a hard bounce scenario
$response = $email
    ->from('you@yourdomain.com')
    ->to('hardbounce@testing.lettermint.co')
    ->subject('Test hard bounce')
    ->text('This will simulate a hard bounce.')
    ->send();

echo "Test email queued: " . $response->message_id;
// Later: webhook fires with message.hard_bounced
```

```python title="Python"
from lettermint import Lettermint
import os

lettermint = Lettermint(api_token=os.environ["LETTERMINT_PROJECT_TOKEN"])

# Test successful delivery
response = lettermint.email \
    .from_("you@yourdomain.com") \
    .to("ok@testing.lettermint.co") \
    .subject("Test delivery") \
    .text("This will simulate successful delivery.") \
    .send()

print(f"Test email queued: {response.message_id}")
# Later: webhook fires with message.delivered
```

```bash title="cURL"
curl -X POST "https://api.lettermint.co/v1/send" \
  -H "Content-Type: application/json" \
  -H "x-lettermint-token: $LETTERMINT_PROJECT_TOKEN" \
  -d '{
    "from": "you@yourdomain.com",
    "to": ["spamcomplaint@testing.lettermint.co"],
    "subject": "Test spam complaint",
    "text": "This will simulate a spam complaint."
  }'

# Response: 202 Accepted
# Later: webhook fires with message.delivered, then message.spam_complaint
```

</CodeTabs>

:::tip
Install the SDK first: `npm install lettermint` (Node.js), `composer require lettermint/lettermint-php` (PHP), or `pip install lettermint` (Python).
:::

## Testing with webhooks

Test addresses are most useful when combined with [webhooks](/platform/webhooks/introduction). Set up a webhook to receive events, then send test emails to verify your handler processes each event type correctly.

### Example: Verify bounce handling

1. Create a webhook subscribed to `message.hard_bounced` events
2. Send to `hardbounce@testing.lettermint.co`
3. Confirm your webhook receives the event and your application handles it (e.g., marks the address as undeliverable)

### Example webhook payload

When sending to `softbounce@testing.lettermint.co`, you'll receive:

```json
{
  "id": "9b0c4a4e-4e29-4d8b-8b3a-3f0f3e6d2f9b",
  "event": "message.soft_bounced",
  "timestamp": "2025-01-31T14:30:00.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Test soft bounce",
    "recipient": "softbounce@testing.lettermint.co",
    "response": {
      "status_code": 452,
      "enhanced_status_code": "4.2.2",
      "content": "Mailbox full"
    },
    "metadata": {},
    "tag": null
  }
}
```

See [Webhook events](/platform/webhooks/events) for the complete payload reference.

## Common testing workflows

### Integration testing

Use test addresses in your CI/CD pipeline to verify email sending works without sending real emails:

```typescript
// In your test suite
describe("Email notifications", () => {
  it("handles bounce events gracefully", async () => {
    // Send to test address
    const response = await email
      .from("app@yourdomain.com")
      .to("hardbounce@testing.lettermint.co")
      .subject("Test")
      .text("Test")
      .send();

    // Verify your webhook handler marks the address as bounced
    // (depends on your application logic)
  });
});
```

### Manual testing

When developing locally, use a tunnel like [ngrok](https://ngrok.com) to expose your webhook endpoint, then send test emails to verify the full flow.

## Troubleshooting

### No webhook received

- **Check webhook is enabled**: Disabled webhooks don't send events
- **Verify event subscription**: Ensure the webhook subscribes to the relevant event type (e.g., `message.soft_bounced`)
- **Allow processing time**: Test events typically arrive within 5-10 seconds
- **Check webhook logs**: View recent deliveries in Dashboard → Route → Webhooks → [Your Webhook]

### API returns an error

- **Verify API token**: Ensure your token is valid and has send permissions
- **Check "from" address**: The sender domain must be [verified](/platform/domains/introduction) in your project

### Test address not recognized

- **Use exact domain**: The domain must be exactly `testing.lettermint.co` (case-insensitive)
- **Check for typos**: Common mistakes: `test.lettermint.co` (wrong), `testing.lettermint.com` (wrong TLD)

## Next steps

<CardGroup cols={2}>
  <Card title="Set up webhooks" icon="webhook" href="/platform/webhooks/introduction">
    Receive delivery events in real-time
  </Card>
  <Card title="Webhook events" icon="list" href="/platform/webhooks/events">
    See all event types and payloads
  </Card>
  <Card title="Verify domains" icon="globe" href="/platform/domains/introduction">
    Configure DNS for sending
  </Card>
  <Card title="API Reference" icon="book" href="/api-reference">
    Complete endpoint documentation
  </Card>
</CardGroup>
