Skip to main content
Resend Docs
current

Search documentation

Type to search this documentation.

On this pageOverview

Reply to Receiving Emails

Reply to Receiving emails in the same thread.

Email clients thread emails by using the message_id metadata.

If you want to reply to an email, add the In-Reply-To header set to the message_id of the received email. To signal the threading, set the subject to start with Re: so that email clients can group the replies together.

The message_id is included in the webhook event payload when an email is received:

JSON
{  "type": "email.received",  "data": {    "email_id": "56761188-7520-42d8-8898-ff6fc54ce618",    "message_id": "<111-222-333@email.example.com>",    "subject": "Sending this example",    "from": "Acme <onboarding@resend.dev>",    "to": ["delivered@resend.dev"]  }}

Use the message_id value from event.data.message_id as the In-Reply-To header when sending your reply.

Here's how you can reply in thread using each SDK:

Node.js
import { Resend, type EmailReceivedEvent } from 'resend';const resend = new Resend('re_xxxxxxxxx');export async function replyToEmail(event: EmailReceivedEvent) {  const messageId = event.data.message_id;  const { data, error } = await resend.emails.send({    from: 'Acme <onboarding@resend.dev>',    to: ['delivered@resend.dev'],    subject: `Re: ${event.data.subject}`,    html: '<p>Thanks for your email!</p>',    headers: {      'In-Reply-To': messageId,    },  });}
PHP
$resend = Resend::client('re_xxxxxxxxx');$event = json_decode(file_get_contents('php://input'), true);$messageId = $event['data']['message_id'];$data = $resend->emails->send([    'from' => 'Acme <onboarding@resend.dev>',    'to' => ['delivered@resend.dev'],    'subject' => "Re: {$event['data']['subject']}",    'html' => '<p>Thanks for your email!</p>',    'headers' => [        'In-Reply-To' => $messageId,    ],]);
Python
import resendresend.api_key = "re_xxxxxxxxx"def handle_email_received(event: resend.EmailReceivedEvent):    message_id = event["data"]["message_id"]    params: resend.Emails.SendParams = {        "from": "Acme <onboarding@resend.dev>",        "to": ["delivered@resend.dev"],        "subject": f"Re: {event['data']['subject']}",        "html": "<p>Thanks for your email!</p>",        "headers": {            "In-Reply-To": message_id,        },    }    email = resend.Emails.send(params)
Ruby
require "resend"Resend.api_key = "re_xxxxxxxxx"message_id = event["data"]["message_id"]params = {    from: "Acme <onboarding@resend.dev>",    to: ["delivered@resend.dev"],    subject: "Re: #{event['data']['subject']}",    html: "<p>Thanks for your email!</p>",    headers: {        "In-Reply-To": message_id,    },}sent = Resend::Emails.send(params)
Go
package mainimport (	"fmt"	"context"	"github.com/resend/resend-go/v4")func main() {    ctx := context.TODO()    client := resend.NewClient("re_xxxxxxxxx")    var event struct {        Data struct {            MessageId string `json:"message_id"`            Subject   string `json:"subject"`        } `json:"data"`    }    messageId := event.Data.MessageId    params := &resend.SendEmailRequest{        From:    "Acme <onboarding@resend.dev>",        To:      []string{"delivered@resend.dev"},        Subject: fmt.Sprintf("Re: %s", event.Data.Subject),        Html:    "<p>Thanks for your email!</p>",        Headers: map[string]string{            "In-Reply-To": messageId,        },    }    sent, err := client.Emails.SendWithContext(ctx, params)    if err != nil {        panic(err)    }    fmt.Println(sent.Id)}
Rust
use resend_rs::events::EmailEvent;use resend_rs::types::CreateEmailBaseOptions;use resend_rs::{Resend, Result};async fn reply(event: EmailEvent) -> Result<()> {    let resend = Resend::new("re_xxxxxxxxx");    let message_id = &event.data.message_id;    let subject = format!("Re: {}", event.data.subject);    let email = CreateEmailBaseOptions::new(        "Acme <onboarding@resend.dev>",        ["delivered@resend.dev"],        &subject,    )    .with_html("<p>Thanks for your email!</p>")    .with_header("In-Reply-To", message_id);    let _email = resend.emails.send(email).await?;    Ok(())}
Java
import com.resend.*;import com.resend.core.exception.ResendException;import com.resend.services.emails.model.CreateEmailOptions;import com.resend.services.emails.model.CreateEmailResponse;import com.resend.services.receiving.model.ReceivedEmail;import java.util.Map;public class Main {    public static void reply(ReceivedEmail event) throws ResendException {        Resend resend = new Resend("re_xxxxxxxxx");        String messageId = event.getMessageId();        CreateEmailOptions params = CreateEmailOptions.builder()                .from("Acme <onboarding@resend.dev>")                .to("delivered@resend.dev")                .subject("Re: " + event.getSubject())                .html("<p>Thanks for your email!</p>")                .headers(Map.of(                    "In-Reply-To", messageId                ))                .build();        CreateEmailResponse data = resend.emails().send(params);    }}
.NET
using Resend;using System.Collections.Generic;IResend resend = ResendClient.Create( "re_xxxxxxxxx" ); // Or from DIasync Task ReplyAsync(ReceivedEmail eventData){    var messageId = eventData.MessageId;    var message = new EmailMessage()    {        From = "Acme <onboarding@resend.dev>",        To = "delivered@resend.dev",        Subject = $"Re: {eventData.Subject}",        HtmlBody = "<p>Thanks for your email!</p>",        Headers = new Dictionary<string, string>()        {            { "In-Reply-To", messageId },        },    };    var resp = await resend.EmailSendAsync(message);}
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": "Re: Sending this example",  "html": "<p>Thanks for your email!</p>",  "headers": {    "In-Reply-To": "<111-222-333@email.example.com>"  }}'
CLI
resend emails send \  --from "Acme <onboarding@resend.dev>" \  --to delivered@resend.dev \  --subject "Re: Sending this example" \  --html "<p>Thanks for your email!</p>" \  --headers "In-Reply-To=<111-222-333@email.example.com>"
Rust
use axum::{
    extract::State,
    response::{IntoResponse, Json, Response},
};
use resend_rs::{types::CreateEmailBaseOptions, Resend};
use serde::Serialize;
use std::sync::Arc;

struct AppState {
    resend: Resend,
}

#[derive(Serialize)]
struct Empty {}

async fn example(
    State(state): State<Arc<AppState>>,
    Json(event): Json<resend_rs::events::EmailEvent>,
) -> Response {
    if matches!(
        event.r#type,
        resend_rs::events::EmailEventType::EmailReceived
    ) {
        let email = CreateEmailBaseOptions::new(
            "Acme <onboarding@resend.dev>",
            vec!["delivered@resend.dev"],
            format!("Re: {}", event.data.subject),
        )
        .with_html("<p>Thanks for your email!</p>")
        .with_header("In-Reply-To", &event.data.message_id);

        let data = state.resend.emails.send(email).await.unwrap();
        Json(data).into_response()
    } else {
        Json(Empty {}).into_response()
    }
}

If you're replying multiple times within the same thread, make sure to also append the previous message_ids to the References header, separated by spaces. This helps email clients maintain the correct threading structure.

Node.js
import { Resend, type EmailReceivedEvent } from 'resend';const resend = new Resend('re_xxxxxxxxx');export async function replyInThread(event: EmailReceivedEvent) {  const previousReferences = ['<msg_id1@domain.com>', '<msg_id2@domain.com>'];  const { data, error } = await resend.emails.send({    from: 'Acme <onboarding@resend.dev>',    to: ['delivered@resend.dev'],    subject: `Re: ${event.data.subject}`,    html: '<p>Thanks for your email!</p>',    headers: {      'In-Reply-To': event.data.message_id,      'References': [...previousReferences, event.data.message_id].join(' '),    },  });}
PHP
$resend = Resend::client('re_xxxxxxxxx');$event = json_decode(file_get_contents('php://input'), true);$previousReferences = ['<msg_id1@domain.com>', '<msg_id2@domain.com>'];$data = $resend->emails->send([    'from' => 'Acme <onboarding@resend.dev>',    'to' => ['delivered@resend.dev'],    'subject' => "Re: {$event['data']['subject']}",    'html' => '<p>Thanks for your email!</p>',    'headers' => [        'In-Reply-To' => $event['data']['message_id'],        'References' => implode(' ', [...$previousReferences, $event['data']['message_id']]),    ],]);
Python
import resendresend.api_key = "re_xxxxxxxxx"def handle_email_received(event: resend.EmailReceivedEvent):    previous_references = ["<msg_id1@domain.com>", "<msg_id2@domain.com>"]    params: resend.Emails.SendParams = {        "from": "Acme <onboarding@resend.dev>",        "to": ["delivered@resend.dev"],        "subject": f"Re: {event['data']['subject']}",        "html": "<p>Thanks for your email!</p>",        "headers": {            "In-Reply-To": event["data"]["message_id"],            "References": " ".join([*previous_references, event["data"]["message_id"]]),        },    }    email = resend.Emails.send(params)
Ruby
require "resend"Resend.api_key = "re_xxxxxxxxx"previous_references = ["<msg_id1@domain.com>", "<msg_id2@domain.com>"]params = {    from: "Acme <onboarding@resend.dev>",    to: ["delivered@resend.dev"],    subject: "Re: #{event['data']['subject']}",    html: "<p>Thanks for your email!</p>",    headers: {        "In-Reply-To": event["data"]["message_id"],        "References": [*previous_references, event["data"]["message_id"]].join(" "),    },}sent = Resend::Emails.send(params)
Go
package mainimport (	"context"	"fmt"	"strings"	"github.com/resend/resend-go/v4")func main() {    ctx := context.TODO()    client := resend.NewClient("re_xxxxxxxxx")    var event struct {        Data struct {            MessageId string `json:"message_id"`            Subject   string `json:"subject"`        } `json:"data"`    }    previousReferences := []string{"<msg_id1@domain.com>", "<msg_id2@domain.com>"}    allReferences := append(previousReferences, event.Data.MessageId)    params := &resend.SendEmailRequest{        From:    "Acme <onboarding@resend.dev>",        To:      []string{"delivered@resend.dev"},        Subject: fmt.Sprintf("Re: %s", event.Data.Subject),        Html:    "<p>Thanks for your email!</p>",        Headers: map[string]string{            "In-Reply-To": event.Data.MessageId,            "References":  strings.Join(allReferences, " "),        },    }    sent, err := client.Emails.SendWithContext(ctx, params)    if err != nil {        panic(err)    }    fmt.Println(sent.Id)}
Rust
use resend_rs::events::EmailEvent;use resend_rs::types::CreateEmailBaseOptions;use resend_rs::{Resend, Result};async fn reply(resend: &Resend, event: EmailEvent) -> Result<()> {    let subject = format!("Re: {}", event.data.subject);    let previous_references = vec!["<msg_id1@domain.com>", "<msg_id2@domain.com>"];    let all_references = [previous_references, vec![event.data.message_id.as_str()]]        .concat()        .join(" ");    let email = CreateEmailBaseOptions::new(        "Acme <onboarding@resend.dev>",        ["delivered@resend.dev"],        &subject,    )    .with_html("<p>Thanks for your email!</p>")    .with_header("In-Reply-To", &event.data.message_id)    .with_header("References", &all_references);    let _email = resend.emails.send(email).await?;    Ok(())}
Java
import com.resend.*;import com.resend.core.exception.ResendException;import com.resend.services.emails.model.CreateEmailOptions;import com.resend.services.emails.model.CreateEmailResponse;import com.resend.services.receiving.model.ReceivedEmail;import java.util.ArrayList;import java.util.List;import java.util.Map;public class Main {    public static void reply(ReceivedEmail event) throws ResendException {        Resend resend = new Resend("re_xxxxxxxxx");        List<String> previousReferences = List.of("<msg_id1@domain.com>", "<msg_id2@domain.com>");        List<String> allReferences = new ArrayList<>(previousReferences);        allReferences.add(event.getMessageId());        CreateEmailOptions params = CreateEmailOptions.builder()                .from("Acme <onboarding@resend.dev>")                .to("delivered@resend.dev")                .subject("Re: " + event.getSubject())                .html("<p>Thanks for your email!</p>")                .headers(Map.of(                    "In-Reply-To", event.getMessageId(),                    "References", String.join(" ", allReferences)                ))                .build();        CreateEmailResponse data = resend.emails().send(params);    }}
.NET
using Resend;IResend resend = ResendClient.Create( "re_xxxxxxxxx" ); // Or from DIasync Task ReplyAsync(ReceivedEmail eventData){    var previousReferences = new List<string> { "<msg_id1@domain.com>", "<msg_id2@domain.com>" };    previousReferences.Add(eventData.MessageId);    var message = new EmailMessage()    {        From = "Acme <onboarding@resend.dev>",        To = "delivered@resend.dev",        Subject = $"Re: {eventData.Subject}",        HtmlBody = "<p>Thanks for your email!</p>",        Headers = new Dictionary<string, string>()        {            { "In-Reply-To", eventData.MessageId },            { "References", string.Join(" ", previousReferences) },        },    };    var resp = await resend.EmailSendAsync(message);}
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": "Re: Sending this example",  "html": "<p>Thanks for your email!</p>",  "headers": {    "In-Reply-To": "<111-222-333@email.example.com>",    "References": "<msg_id1@domain.com> <msg_id2@domain.com> <111-222-333@email.example.com>"  }}'
CLI
resend emails send \  --from "Acme <onboarding@resend.dev>" \  --to delivered@resend.dev \  --subject "Re: Sending this example" \  --html "<p>Thanks for your email!</p>" \  --headers "In-Reply-To=<111-222-333@email.example.com>" \    "References=<msg_id1@domain.com> <msg_id2@domain.com> <111-222-333@email.example.com>"
Rust
use resend_rs::{events::EmailEvent, types::CreateEmailBaseOptions, Resend};

async fn reply(resend: &Resend, event: EmailEvent) {
    let previous_references = [
        "<msg_id1@domain.com>",
        "<msg_id2@domain.com>",
        &event.data.message_id,
    ];

    let email = CreateEmailBaseOptions::new(
        "Acme <onboarding@resend.dev>",
        vec!["delivered@resend.dev"],
        format!("Re: {}", event.data.subject),
    )
    .with_html("<p>Thanks for your email!</p>")
    .with_header("In-Reply-To", &event.data.message_id)
    .with_header("References", &previous_references.join(" "));

    let data = resend.emails.send(email).await.unwrap();
}
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu