Forward Received Emails
Received emails can also be forwarded to another email address.
Using the forward helper method
Section titled “Using the forward helper method”The Node.js SDK provides a forward() helper method that simplifies forwarding received emails. This method automatically handles fetching the email content and attachments.
Here's how you can implement this:
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { Resend } from 'resend';
const resend = new Resend('re_xxxxxxxxx');
export const POST = async (request: NextRequest) => {
const event = await request.json();
if (event.type === 'email.received') {
const { data, error } = await resend.emails.receiving.forward({
emailId: event.data.email_id,
to: 'delivered@resend.dev',
from: 'onboarding@resend.dev',
});
if (error) {
return new NextResponse(`Error: ${error.message}`, { status: 500 });
}
return NextResponse.json(data);
}
return NextResponse.json({});
};use axum::{
extract::State,
http::StatusCode,
response::{IntoResponse, Json, Response},
};
use resend_rs::{
types::{ForwardReceivingEmail, InboundEmailId},
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>,
) -> Result<Response, Response> {
if matches!(
event.r#type,
resend_rs::events::EmailEventType::EmailReceived
) {
let opts = ForwardReceivingEmail::new(
InboundEmailId::new(&event.data.email_id),
"onboarding@resend.dev",
vec!["delivered@resend.dev"],
);
let data = state.resend.receiving.forward(opts).await.map_err(|e| {
(StatusCode::INTERNAL_SERVER_ERROR, format!("Error: {}", e)).into_response()
})?;
Ok(Json(data).into_response())
} else {
Ok(Json(Empty {}).into_response())
}
}By default, the forward method forwards the email in a way that preserves the original email content and attachments exactly as received.
Alternatively, you can forward emails as if they had been forwarded through an email client, with the forwarded message footer. For that, use passthrough: false and provide custom text or HTML content. The original email will be shown after the forwarded message footer:
import { Resend, type EmailReceivedEvent } from 'resend';
const resend = new Resend('re_xxxxxxxxx');
export async function forwardEmail(event: EmailReceivedEvent) {
const { data, error } = await resend.emails.receiving.forward({
emailId: event.data.email_id,
to: 'delivered@resend.dev',
from: 'onboarding@resend.dev',
passthrough: false,
text: 'See attached forwarded message.',
html: '<p>See attached forwarded message.</p>',
});
}use resend_rs::{
events::EmailEvent,
types::{ForwardReceivingEmail, InboundEmailId},
Resend,
};
async fn forward(resend: &Resend, event: EmailEvent) {
let opts = ForwardReceivingEmail::new(
InboundEmailId::new(&event.data.email_id),
"onboarding@resend.dev",
vec!["delivered@resend.dev"],
)
.with_passthrough(false)
.with_text("See attached forwarded message.")
.with_html("<p>See attached forwarded message.</p>");
let data = resend.receiving.forward(opts).await;
}Manual forwarding
Section titled “Manual forwarding”If you're not using Node.js or prefer not to use the forward helper method, you can manually forward received emails using the Send Email API.
The recommended approach is to download the raw email and parse it to properly extract content and attachments (especially for inline images). Then, you can send a new email with the extracted content and attachments using the Send Email API.
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { Resend } from 'resend';
import { simpleParser } from 'mailparser';
const resend = new Resend('re_xxxxxxxxx');
export const POST = async (request: NextRequest) => {
const event = await request.json();
if (event.type === 'email.received') {
// Get the email metadata
const { data: email } = await resend
.emails
.receiving
.get(event.data.email_id);
// Download the raw email content if available
if (!email?.raw?.download_url) {
return new NextResponse('Raw email not available', { status: 500 });
}
const rawResponse = await fetch(email.raw.download_url);
const rawEmailContent = await rawResponse.text();
// Parse the raw email to extract content and attachments
const parsed = await simpleParser(rawEmailContent, {
skipImageLinks: true,
});
// Extract attachments with content_id for inline images
const attachments = parsed.attachments.map((attachment) => {
// Strip < and > from content IDs for proper inline image handling
const contentId = attachment.contentId
? attachment.contentId.replace(/^<|>$/g, '')
: undefined;
return {
filename: attachment.filename,
content: attachment.content.toString('base64'),
contentType: attachment.contentType,
contentId: contentId || undefined,
};
});
const { data, error } = await resend.emails.send({
from: 'Acme <onboarding@resend.dev>',
to: ['delivered@resend.dev'],
subject: email.subject || '(no subject)',
html: parsed.html || undefined,
text: parsed.text || '',
attachments: attachments.length > 0 ? attachments : undefined,
});
if (error) {
return new NextResponse(`Error: ${error.message}`, { status: 500 });
}
return NextResponse.json(data);
}
return NextResponse.json({});
};