---
title: "Batch Validation Modes"
slug: batch-validation-modes
description: Use batch validation modes to control how emails are validated in batch sending.
created_at: "2025-09-19"
updated_at: "2025-09-19"
image: https://cdn.resend.com/posts/batch-validation-modes.jpg
humans: ["pedro-gomes"]
---

We recently enabled a new feature to help you control how emails are validated in batch sending.

Choose between two modes:

- **Strict mode (default):** sends the batch only if all emails in the request are valid.
- **Permissive mode:** processes all emails, allowing for partial success and returning validation errors if present.

Traditionally, the Resend API enforced a strict validation mode, failing the batch if any email in your payload was invalid (e.g., required fields are missing, fields contain invalid data, etc.).

The new permissive mode, however, allows for more flexibility. Now, sending a batch of emails with an invalid payload for some emails, will not fail the entire batch. Instead, valid emails will be queued and invalid emails will be returned in the `errors` array.

## How does it work?

Set the batch validation header to `permissive` to enable the new permissive mode (otherwise **strict** mode automatically applies).

<CodeTabs codeHeight={475}>

```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const { data, errors } = await resend.batch.send(
  [
    {
      from: 'Acme <onboarding@resend.dev>',
      to: ['foo@gmail.com'],
      subject: 'hello world',
      html: '<h1>it works!</h1>',
    },
    {
      from: 'Acme <onboarding@resend.dev>',
      to: ['bar@outlook.com'],
      subject: 'world hello',
      html: '<p>it works!</p>',
    },
  ],
  {
    --highlight-start
    batchValidation: 'permissive',
    --highlight-end
  },
);
```

```php
$resend = Resend::client('re_xxxxxxxxx');

$resend->batch->send(
  [
    [
      'from' => 'Acme <onboarding@resend.dev>',
      'to' => ['foo@gmail.com'],
      'subject' => 'hello world',
      'html' => '<h1>it works!</h1>',
    ],
    [
      'from' => 'Acme <onboarding@resend.dev>',
      'to' => ['bar@outlook.com'],
      'subject' => 'world hello',
      'html' => '<p>it works!</p>',
    ]
  ],
  [
    --highlight-start
    'batch_validation' => 'permissive',
    --highlight-end
  ]
);
```

```python
import resend
from typing import List

resend.api_key = "re_xxxxxxxxx"

params: List[resend.Emails.SendParams] = [
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["foo@gmail.com"],
    "subject": "hello world",
    "html": "<h1>it works!</h1>",
  },
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["bar@outlook.com"],
    "subject": "world hello",
    "html": "<p>it works!</p>",
  }
]

options: resend.Batch.SendOptions = {
  --highlight-start
  "batch_validation": "permissive",
  --highlight-end
}

resend.Batch.send(params, options)
```

```ruby
require "resend"

Resend.api_key = 're_xxxxxxxxx'

params = [
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["foo@gmail.com"],
    "subject": "hello world",
    "html": "<h1>it works!</h1>",
  },
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["bar@outlook.com"],
    "subject": "world hello",
    "html": "<p>it works!</p>",
  }
]

Resend::Batch.send(
  params,
  --highlight-start
  options: { batch_validation: "permissive" }
  --highlight-end
)
```

```go
package examples

import (
	"fmt"
	"os"

	"github.com/resend/resend-go/v2"
)

func main() {

  ctx := context.TODO()

  client := resend.NewClient("re_xxxxxxxxx")

  var batchEmails = []*resend.SendEmailRequest{
    {
      From:    "Acme <onboarding@resend.dev>",
      To:      []string{"foo@gmail.com"},
      Subject: "hello world",
      Html:    "<h1>it works!</h1>",
    },
    {
      From:    "Acme <onboarding@resend.dev>",
      To:      []string{"bar@outlook.com"},
      Subject: "world hello",
      Html:    "<p>it works!</p>",
    },
  }

  options := &resend.BatchSendEmailOptions{
    --highlight-start
    BatchValidation: "permissive",
    --highlight-end
  }

  sent, err := client.Batch.SendWithOptions(ctx, batchEmails, options)

  if err != nil {
    panic(err)
  }
  fmt.Println(sent.Data)
}
```

```rust
use resend_rs::types::{BatchValidation, CreateEmailBaseOptions};
use resend_rs::{Resend, Result};

#[tokio::main]
async fn main() -> Result<()> {
  let resend = Resend::new("re_xxxxxxxxx");

  let emails = vec![
    CreateEmailBaseOptions::new(
      "Acme <onboarding@resend.dev>",
      vec!["foo@gmail.com"],
      "hello world",
    )
    .with_html("<h1>it works!</h1>"),
    CreateEmailBaseOptions::new(
      "Acme <onboarding@resend.dev>",
      vec!["bar@outlook.com"],
      "world hello",
    )
    .with_html("<p>it works!</p>"),
  ];

  let _emails = resend
    .batch
    --highlight-start
    .send_with_batch_validation(emails, BatchValidation::Permissive)
    --highlight-end
    .await?;

  Ok(())
}
```

```java
import com.resend.*;

public class Main {
    public static void main(String[] args) {

        Resend resend = new Resend("re_xxxxxxxxx");

        CreateEmailOptions firstEmail = CreateEmailOptions.builder()
            .from("Acme <onboarding@resend.dev>")
            .to("foo@gmail.com")
            .subject("hello world")
            .html("<h1>it works!</h1>")
            .build();

        CreateEmailOptions secondEmail = CreateEmailOptions.builder()
            .from("Acme <onboarding@resend.dev>")
            .to("bar@outlook.com")
            .subject("world hello")
            .html("<p>it works!</p>")
            .build();

        RequestOptions options = RequestOptions.builder()
            .add("x-batch-validation", "permissive")
            .build();

        CreateBatchEmailsResponse data = resend.batch()
          .send(
            Arrays.asList(firstEmail, secondEmail),
            options
          );
    }
}
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" ); // Or from DI

var mail1 = new EmailMessage()
{
    From = "Acme <onboarding@resend.dev>",
    To = "foo@gmail.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
};

var mail2 = new EmailMessage()
{
    From = "Acme <onboarding@resend.dev>",
    To = "bar@outlook.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
};

var resp = await resend.EmailBatchAsync(
    [ mail1, mail2 ],
    EmailBatchValidationMode.Permissive
);

Console.WriteLine( "Nr Emails={0}", resp.Content.Data.Count );

if ( resp.Content.Errors?.Count > 0 )
{
    foreach ( var error in resp.Content.Errors )
    {
        Console.WriteLine( "Error at index {0}: {1}", error.Index, error.Message );
    }
}
```

```curl
curl -X POST 'https://api.resend.com/emails/batch' \
     -H 'Authorization: Bearer re_xxxxxxxxx' \
     -H 'Content-Type: application/json' \
     --highlight-start
     -H 'x-batch-validation: permissive' \
     --highlight-end
     -d $'[
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["foo@gmail.com"],
    "subject": "hello world",
    "html": "<h1>it works!</h1>"
  },
  {
    "from": "Acme <onboarding@resend.dev>",
    "to": ["bar@outlook.com"],
    "subject": "world hello",
    "html": "<p>it works!</p>"
  }
]'
```
</CodeTabs>

## Example response

With **strict mode** enabled, the batch will only be sent if all emails are valid. A successful response will return the ids of the queued emails:

```bash
{
  "data": [
    {
      "id": "ae2014de-c168-4c61-8267-70d2662a1ce1"
    },
    {
      "id": "faccb7a5-8a28-4e9a-ac64-8da1cc3bc1cb"
    }
  ]
}
```

With **permissive mode** enabled, the batch will be sent even if some emails are invalid. The `data` array returns all valid emails and the `errors` array includes the invalid emails and the reason they couldn't be created.

```bash
{
  "data": [
    {
      "id": "ae2014de-c168-4c61-8267-70d2662a1ce1"
    },
    {
      "id": "faccb7a5-8a28-4e9a-ac64-8da1cc3bc1cb"
    }
  ],
  "errors": [
    {
      "index": 2, // 0-indexed (first item is index 0)
      "message": "The `to` field is missing."
    }
  ]
}
```

Note that the index references the email index in the payload of your request.

## Understanding errors

If an email is invalid, it means Resend was unable to create it in our system.

Reasons your email may cause an error include:

- Required fields are missing.
- Fields contain invalid data.
- The batch contains more than 100 emails.

Importantly, this means the following:

- The email will not appear in the dashboard, since it could not be created.
- The error object will be included in the `errors` array.
- The only way to understand why the email failed is to inspect the returned error object.

For more details, see our [Batch Validation Mode documentation](/docs/dashboard/emails/batch-validation-modes). We hope this additional flexibility empowers you to send emails with more confidence and recovery from failures more gracefully.

And as always, [our team of email experts](https://resend.com/support) is here to help you troubleshoot any issues you may encounter.