> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mailbreeze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Understanding and handling MailBreeze API errors

## Error Response Format

When an error occurs, the API returns a JSON response with an `error` object:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid email address format",
    "details": {
      "field": "to",
      "value": "invalid-email"
    }
  },
  "meta": {
    "timestamp": "2024-01-15T10:30:00.000Z",
    "requestId": "req_abc123",
    "path": "/api/v1/emails"
  }
}
```

## HTTP Status Codes

| Status | Meaning                                   |
| ------ | ----------------------------------------- |
| `200`  | Success                                   |
| `201`  | Created                                   |
| `400`  | Bad Request - Invalid parameters          |
| `401`  | Unauthorized - Invalid or missing API key |
| `403`  | Forbidden - Insufficient permissions      |
| `404`  | Not Found - Resource doesn't exist        |
| `409`  | Conflict - Resource already exists        |
| `422`  | Unprocessable Entity - Validation failed  |
| `429`  | Too Many Requests - Rate limit exceeded   |
| `500`  | Internal Server Error                     |

## Error Codes

### Authentication Errors

| Code           | HTTP Status | Description                               |
| -------------- | ----------- | ----------------------------------------- |
| `UNAUTHORIZED` | 401         | Missing or invalid API key                |
| `KEY_REVOKED`  | 401         | API key has been revoked                  |
| `KEY_EXPIRED`  | 401         | API key has expired                       |
| `FORBIDDEN`    | 403         | API key doesn't have required permissions |

### Validation Errors

| Code                     | HTTP Status | Description                     |
| ------------------------ | ----------- | ------------------------------- |
| `VALIDATION_ERROR`       | 400         | Request body validation failed  |
| `INVALID_EMAIL`          | 400         | Email address format is invalid |
| `MISSING_REQUIRED_FIELD` | 400         | Required field not provided     |
| `INVALID_PARAMETER`      | 400         | Query parameter is invalid      |

### Domain Errors

| Code                      | HTTP Status | Description                           |
| ------------------------- | ----------- | ------------------------------------- |
| `DNS_VERIFICATION_FAILED` | 400         | Domain DNS records not verified       |
| `DOMAIN_NOT_VERIFIED`     | 400         | Domain verification incomplete        |
| `FROM_DOMAIN_MISMATCH`    | 400         | From address must use verified domain |
| `DOMAIN_NOT_FOUND`        | 404         | Domain not found in account           |

### Email Sending Errors

| Code                    | HTTP Status | Description                           |
| ----------------------- | ----------- | ------------------------------------- |
| `SENDING_DISABLED`      | 403         | Email sending is disabled for domain  |
| `RECIPIENT_SUPPRESSED`  | 400         | Recipient is on suppression list      |
| `ATTACHMENT_NOT_FOUND`  | 400         | Referenced attachment doesn't exist   |
| `ATTACHMENT_TOO_LARGE`  | 400         | Attachment exceeds size limit         |
| `TEMPLATE_NOT_FOUND`    | 404         | Template ID doesn't exist             |
| `TEMPLATE_RENDER_ERROR` | 400         | Template variable substitution failed |

### Contact Errors

| Code                     | HTTP Status | Description                               |
| ------------------------ | ----------- | ----------------------------------------- |
| `CONTACT_NOT_FOUND`      | 404         | Contact doesn't exist                     |
| `CONTACT_ALREADY_EXISTS` | 409         | Contact with email already exists in list |
| `LIST_NOT_FOUND`         | 404         | Contact list doesn't exist                |
| `INVALID_CUSTOM_FIELD`   | 400         | Custom field name or value invalid        |

### Verification Errors

| Code                   | HTTP Status | Description                           |
| ---------------------- | ----------- | ------------------------------------- |
| `VERIFICATION_FAILED`  | 400         | Email verification could not complete |
| `BATCH_TOO_LARGE`      | 400         | Batch verification exceeds limit      |
| `INSUFFICIENT_CREDITS` | 402         | Not enough verification credits       |

### Rate Limiting

| Code                  | HTTP Status | Description       |
| --------------------- | ----------- | ----------------- |
| `RATE_LIMIT_EXCEEDED` | 429         | Too many requests |

When rate limited, check response headers:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 2024-01-01T12:01:00Z
Retry-After: 60
```

## Handling Errors in SDKs

<CodeGroup>
  ```typescript JavaScript theme={null}
  import { MailBreeze, MailBreezeError } from "mailbreeze";

  const mailbreeze = new MailBreeze({ apiKey: "sk_live_xxx" });

  try {
    await mailbreeze.emails.send({
      from: "hello@yourdomain.com",
      to: "invalid-email",
      subject: "Test",
    });
  } catch (error) {
    if (error instanceof MailBreezeError) {
      console.log(error.code);    // "INVALID_EMAIL"
      console.log(error.message); // "Invalid email address format"
      console.log(error.status);  // 400
    }
  }
  ```

  ```python Python theme={null}
  from mailbreeze import MailBreeze, MailBreezeError

  client = MailBreeze(api_key="sk_live_xxx")

  try:
      await client.emails.send(
          from_="hello@yourdomain.com",
          to="invalid-email",
          subject="Test",
      )
  except MailBreezeError as e:
      print(e.code)     # "INVALID_EMAIL"
      print(e.message)  # "Invalid email address format"
      print(e.status)   # 400
  ```

  ```go Go theme={null}
  client := mailbreeze.NewClient("sk_live_xxx")

  email, err := client.Emails.Send(ctx, &mailbreeze.SendEmailParams{
      From:    "hello@yourdomain.com",
      To:      []string{"invalid-email"},
      Subject: "Test",
  })

  if err != nil {
      var mbErr *mailbreeze.Error
      if errors.As(err, &mbErr) {
          fmt.Println(mbErr.Code)    // "INVALID_EMAIL"
          fmt.Println(mbErr.Message) // "Invalid email address format"
          fmt.Println(mbErr.Status)  // 400
      }
  }
  ```

  ```php PHP theme={null}
  use MailBreeze\MailBreeze;
  use MailBreeze\Exceptions\MailBreezeException;

  $mailbreeze = new MailBreeze('sk_live_xxx');

  try {
      $mailbreeze->emails->send([
          'from' => 'hello@yourdomain.com',
          'to' => 'invalid-email',
          'subject' => 'Test',
      ]);
  } catch (MailBreezeException $e) {
      echo $e->getCode();    // "INVALID_EMAIL"
      echo $e->getMessage(); // "Invalid email address format"
      echo $e->getStatus();  // 400
  }
  ```

  ```rust Rust theme={null}
  use mailbreeze::{Client, Error};

  let client = Client::new("sk_live_xxx");

  match client.emails().send(SendEmailParams {
      from: "hello@yourdomain.com".to_string(),
      to: vec!["invalid-email".to_string()],
      subject: Some("Test".to_string()),
      ..Default::default()
  }).await {
      Ok(email) => println!("Sent: {}", email.id),
      Err(Error::Api { code, message, status }) => {
          println!("Code: {}", code);    // "INVALID_EMAIL"
          println!("Message: {}", message); // "Invalid email address format"
          println!("Status: {}", status);   // 400
      }
      Err(e) => println!("Other error: {}", e),
  }
  ```
</CodeGroup>

## Retry Strategy

For transient errors (5xx status codes and rate limits), implement exponential backoff:

```typescript theme={null}
async function sendWithRetry(params, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await mailbreeze.emails.send(params);
    } catch (error) {
      if (error.status >= 500 || error.status === 429) {
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error; // Don't retry client errors
    }
  }
  throw new Error("Max retries exceeded");
}
```

<Note>
  The official SDKs include automatic retry logic with exponential backoff for transient errors.
</Note>
