---
title: "Introducing the Schedule Email API"
slug: introducing-the-schedule-email-api
description: "Send emails at a specific time without additional complexity."
created_at: "2024-08-19"
updated_at: "2024-11-28"
image: https://cdn.resend.com/posts/introducing-the-schedule-email-api.jpg
humans: ["felipe-volpone"]
featured: false
category: "product"
---

While some emails need to be delivered as soon as possible, like password resets or magic links, others can be scheduled for a specific time.

Here are some examples of when you might want to schedule an email:
- Send welcome email **5 minutes after** signup
- Trigger a reminder email **24 hours before** an event
- Schedule a weekly digest email for the **next day at 9am PST**

Before, you had to use external services to handle the scheduling logic, but now you can use the new Resend API to schedule emails.

## Schedule an email

You can use the various Resend SDKs to schedule emails.

<CodeTabs codeHeight={300}>
```nodejs
import { Resend } from 'resend';

const resend = new Resend('re_xxxxxxxxx');

const oneMinuteFromNow = new Date(Date.now() + 1000 * 60).toISOString();

await resend.emails.send({
  from: 'Acme <onboarding@resend.dev>',
  to: ['delivered@resend.dev'],
  subject: 'hello world',
  html: '<p>it works!</p>',
  scheduledAt: oneMinuteFromNow,
});
```

```ruby
require "resend"

Resend.api_key = "re_xxxxxxxxx"

one_minute_from_now = (Time.now + 1 * 60).strftime("%Y-%m-%dT%H:%M:%S.%L%z")

params = {
  "from": "Acme <onboarding@resend.dev>",
  "to": ["delivered@resend.dev"],
  "subject": "hello world",
  "html": "<p>it works!</p>",
  "scheduled_at": one_minute_from_now
}

Resend::Emails.send(params)
```

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

$oneMinuteFromNow = (new DateTime())->modify('+1 minute')->format(DateTime::ISO8601);

$resend->emails->send([
  'from' => 'Acme <onboarding@resend.dev>',
  'to' => ['delivered@resend.dev'],
  'subject' => 'hello world',
  'html' => '<p>it works!</p>',
  'scheduled_at' => $oneMinuteFromNow
]);
```

```python
import resend
from datetime import datetime, timedelta

resend.api_key = "re_xxxxxxxxx"

one_minute_from_now = (datetime.now() + timedelta(minutes=1)).isoformat()

params: resend.Emails.SendParams = {
  "from": "Acme <onboarding@resend.dev>",
  "to": ["delivered@resend.dev"],
  "subject": "hello world",
  "html": "<p>it works!</p>",
  "scheduled_at": one_minute_from_now
}

resend.Emails.send(params)
```

```go
import (
	"fmt"

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

func main() {
  ctx := context.TODO()
  client := resend.NewClient("re_xxxxxxxxx")

  oneMinuteFromNow := time.Now().Add(time.Minute * time.Duration(1))
  oneMinuteFromNowISO := oneMinuteFromNow.Format("2006-01-02T15:04:05-0700")

  params := &resend.SendEmailRequest{
    From:        "Acme <onboarding@resend.dev>",
    To:          []string{"delivered@resend.dev"},
    Subject:     "hello world",
    Html:        "<p>it works!</p>",
    ScheduledAt: oneMinuteFromNowISO
  }

  sent, err := client.Emails.SendWithContext(ctx, params)

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

```rust
use chrono::{Local, TimeDelta};
use resend_rs::types::CreateEmailBaseOptions;
use resend_rs::{Resend, Result};

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

  let from = "Acme <onboarding@resend.dev>";
  let to = ["delivered@resend.dev"];
  let subject = "hello world";
  let one_minute_from_now = Local::now()
    .checked_add_signed(TimeDelta::minutes(1))
    .unwrap()
    .to_rfc3339();

  let email = CreateEmailBaseOptions::new(from, to, subject)
    .with_html("<p>it works!</p>")
    .with_scheduled_at(&one_minute_from_now);

  let _email = resend.emails.send(email).await?;

  Ok(())
}
```

```java
import com.resend.*;

public class Main {
    public static void main(String[] args) {
        Resend resend = new Resend("re_xxxxxxxxx");

        String oneMinuteFromNow = Instant
          .now()
          .plus(1, ChronoUnit.MINUTES)
          .toString();

        CreateEmailOptions params = CreateEmailOptions.builder()
                .from("Acme <onboarding@resend.dev>")
                .to("delivered@resend.dev")
                .subject("hello world")
                .html("<p>it works!</p>")
                .scheduledAt(oneMinuteFromNow)
                .build();

        CreateEmailResponse data = resend.emails().send(params);
    }
}
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

var resp = await resend.EmailSendAsync( new EmailMessage()
{
    From = "Acme <onboarding@resend.dev>",
    To = "delivered@resend.dev",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
    MomentSchedule = DateTime.UtcNow.AddMinutes( 1 ),
} );
Console.WriteLine( "Email Id={0}", resp.Content );
```

```curl
curl -X POST 'https://api.resend.com/emails' \
 -H 'Authorization: Bearer re_xxxxxxxxx' \
 -H 'Content-Type: application/json' \
 -d $'{
  "from": "Acme <onboarding@resend.dev>",
  "to": ["delivered@resend.dev"],
  "subject": "hello world",
  "html": "<p>it works!</p>",
  "scheduled_at": "2024-08-20T11:52:01.858Z"
}'
```
</CodeTabs>

The date must be in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format (e.g: `2024-08-05T11:52:01.858Z`).

<Callout type="info">
  <span>Emails can be scheduled up to 72 hours in advance.</span>
</Callout>

Once you schedule an email, you can see the scheduled time in the Resend dashboard.

<video
  src="https://cdn.resend.com/posts/introducing-the-schedule-email-api-1.mp4"
  autoPlay
  loop
  muted
  playsInline
  onClick="this.controls = true"
  className="extraWidth"
/>

## Reschedule an email

After scheduling an email, you might need to update the scheduled time.

You can do so with the following method:

<CodeTabs codeHeight={160}>
```nodejs
const oneMinuteFromNow = new Date(Date.now() + 1000 * 60).toISOString();

resend.emails.update({
  id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
  scheduledAt: oneMinuteFromNow,
});
```

```php
$oneMinuteFromNow = (new DateTime())->modify('+1 minute')->format(DateTime::ISO8601);

$resend->emails->update('49a3999c-0ce1-4ea6-ab68-afcd6dc2e794', [
  'scheduled_at' => $oneMinuteFromNow
]);
```

```python
one_minute_from_now = (datetime.now() + timedelta(minutes=1)).isoformat()

update_params: resend.Emails.UpdateParams = {
  "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
  "scheduled_at": one_minute_from_now
}

resend.Emails.update(params=update_params)
```

```ruby
one_minute_from_now = (Time.now + 1 * 60).strftime("%Y-%m-%dT%H:%M:%S.%L%z")

update_params = {
  "email_id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
  "scheduled_at": one_minute_from_now
}

updated_email = Resend::Emails.update(update_params)
```

```go
oneMinuteFromNow := time.Now().Add(time.Minute * time.Duration(1))
oneMinuteFromNowISO := oneMinuteFromNow.Format("2006-01-02T15:04:05-0700")

updateParams := &resend.UpdateEmailRequest{
  Id:          "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
  ScheduledAt: oneMinuteFromNowISO
}

updatedEmail, err := client.Emails.Update(updateParams)

if err != nil {
  panic(err)
}
fmt.Printf("%v\n", updatedEmail)
```

```rust
let one_minute_from_now = Local::now()
  .checked_add_signed(TimeDelta::minutes(1))
  .unwrap()
  .to_rfc3339();

let update = UpdateEmailOptions::new()
  .with_scheduled_at(&one_minute_from_now);

let _email = resend
  .emails
  .update("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794", update)
  .await?;
```

```java
String oneMinuteFromNow = Instant
  .now()
  .plus(1, ChronoUnit.MINUTES)
  .toString();

UpdateEmailOptions updateParams = UpdateEmailOptions.builder()
  .scheduledAt(oneMinuteFromNow)
  .build();

UpdateEmailResponse data = resend.emails().update("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794", updateParams);
```

```dotnet
using Resend;

IResend resend = ResendClient.Create( "re_xxxxxxxxx" );

await resend.EmailRescheduleAsync(
    new Guid( "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794" ),
    DateTime.UtcNow.AddMinutes( 1 ) );
```

```curl
curl -X PATCH 'https://api.resend.com/emails/49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' \
 -H 'Authorization: Bearer re_xxxxxxxxx' \
 -H 'Content-Type: application/json' \
 -d $'{
  "scheduled_at": "2024-08-05T11:52:01.858Z"
}'
```
</CodeTabs>

You can also reschedule an email directly in the Resend dashboard.

<video
  src="https://cdn.resend.com/posts/introducing-the-schedule-email-api-2.mp4"
  autoPlay
  loop
  muted
  playsInline
  onClick="this.controls = true"
  className="extraWidth"
/>

## Cancel a scheduled email

If you need to cancel a scheduled email, you can do so with the following code:

<CodeTabs codeHeight={120}>
```nodejs
resend.emails.cancel('49a3999c-0ce1-4ea6-ab68-afcd6dc2e794');
```

```php
$resend->emails->cancel('49a3999c-0ce1-4ea6-ab68-afcd6dc2e794');
```

```python
resend.Emails.cancel(email_id="49a3999c-0ce1-4ea6-ab68-afcd6dc2e794")
```

```ruby
Resend::Emails.cancel("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794")
```

```go
canceled, err := client.Emails.Cancel("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794")
if err != nil {
  panic(err)
}
fmt.Println(canceled.Id)
```

```rust
let _canceled = resend
  .emails
  .cancel("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794")
  .await?;
```

```java
CancelEmailResponse canceled = resend
  .emails()
  .cancel("49a3999c-0ce1-4ea6-ab68-afcd6dc2e794");
```

```dotnet
await resend.EmailCancelAsync( new Guid( "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794" ) );
```

```curl
curl -X POST 'https://api.resend.com/emails/49a3999c-0ce1-4ea6-ab68-afcd6dc2e794/cancel' \
 -H 'Authorization: Bearer re_xxxxxxxxx' \
 -H 'Content-Type: application/json'
```
</CodeTabs>

<Callout type="info">
  <span>Once an email is canceled, it cannot be rescheduled.</span>
</Callout>

You can also cancel a scheduled email in the Resend dashboard.

<video
  src="https://cdn.resend.com/posts/introducing-the-schedule-email-api-3.mp4"
  autoPlay
  loop
  muted
  playsInline
  onClick="this.controls = true"
  className="extraWidth"
/>

## Limitations

There are some limitations to keep in mind when scheduling emails:

- Batch emails cannot be scheduled
- Emails sent via SMTP cannot be scheduled
- Emails with attachments cannot be scheduled

## Get started

We hope this new endpoint makes it easier for you to schedule emails in your application without having to introduce additional complexity.

You can see the [Resend OpenAPI spec](https://github.com/resend/resend-openapi) or the [Postman collection](https://www.postman.com/resend/workspace/resend-api/collection/78558-536fcef8-4f87-42a5-ae1a-57f891ef1404) for all parameters.

Feel free to check the [documentation](https://resend.com/docs/api-reference/emails/send-email) for more details.
