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. We also recommend setting the subject to start with Re: so that email clients can group the replies together.
Get the message ID
Themessage_id is included in the webhook event payload when an email is received:
{
"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"]
}
}
message_id value from event.data.message_id as the In-Reply-To header when sending your reply.
Send a reply in thread
Here’s how you can reply in thread using each SDK:import { Resend } from 'resend';
const resend = new Resend('re_xxxxxxxxx');
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,
},
});
$resend = Resend::client('re_xxxxxxxxx');
$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,
],
]);
import resend
resend.api_key = "re_xxxxxxxxx"
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)
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)
import (
"fmt"
"context"
"github.com/resend/resend-go/v3"
)
func main() {
ctx := context.TODO()
client := resend.NewClient("re_xxxxxxxxx")
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)
}
use resend_rs::types::CreateEmailBaseOptions;
use resend_rs::{Resend, Result};
#[tokio::main]
async fn main() -> Result<()> {
let resend = Resend::new("re_xxxxxxxxx");
let message_id = &event.data.received.unwrap().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(())
}
import com.resend.*;
public class Main {
public static void main(String[] args) {
Resend resend = new Resend("re_xxxxxxxxx");
String messageId = event.getData().getMessageId();
CreateEmailOptions params = CreateEmailOptions.builder()
.from("Acme <onboarding@resend.dev>")
.to("delivered@resend.dev")
.subject("Re: " + event.getData().getSubject())
.html("<p>Thanks for your email!</p>")
.headers(Map.of(
"In-Reply-To", messageId
))
.build();
CreateEmailResponse data = resend.emails().send(params);
}
}
using Resend;
using System.Collections.Generic;
IResend resend = ResendClient.Create("re_xxxxxxxxx");
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 -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>"
}
}'
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.received.unwrap().message_id);
let data = state.resend.emails.send(email).await.unwrap();
Json(data).into_response()
} else {
Json(Empty {}).into_response()
}
}
Replying multiple times in a thread
If you’re replying multiple times within the same thread, make sure to also append the previousmessage_ids to the References header, separated by spaces.
This helps email clients maintain the correct threading structure.
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(' '),
},
});
$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']]),
],
]);
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)
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)
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)
let previous_references = vec!["<msg_id1@domain.com>", "<msg_id2@domain.com>"];
let all_references = [previous_references, vec![&event.data.message_id]]
.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?;
List<String> previousReferences = List.of("<msg_id1@domain.com>", "<msg_id2@domain.com>");
List<String> allReferences = new ArrayList<>(previousReferences);
allReferences.add(event.getData().getMessageId());
CreateEmailOptions params = CreateEmailOptions.builder()
.from("Acme <onboarding@resend.dev>")
.to("delivered@resend.dev")
.subject("Re: " + event.getData().getSubject())
.html("<p>Thanks for your email!</p>")
.headers(Map.of(
"In-Reply-To", event.getData().getMessageId(),
"References", String.join(" ", allReferences)
))
.build();
CreateEmailResponse data = resend.emails().send(params);
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 -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>"
}
}'
let received = &event.data.received.unwrap();
let previous_references = [
"<msg_id1@domain.com>",
"<msg_id2@domain.com>",
&received.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", &received.message_id)
.with_header("References", &previous_references.join(" "));
let data = state.resend.emails.send(email).await.unwrap();