← Vytvářejte agenty na Cloudflare / agents / examples
E-mailový agent
Agents mohou odesílat a přijímat e-maily pomocí Cloudflare Email Service. Tento návod ukazuje, jak pomocí vazby Workers odesílat odchozí e-maily, směrovat příchozí poštu do Agents a bezpečně zpracovávat navazující odpovědi.
Předpoklady
Než začnete s Agents používat e-mail, potřebujete:
- Doména zapojená do Cloudflare Email Service.
- A
send_emailvazba vwrangler.jsoncpro odchozí e-maily. - Směrovací pravidlo Email Service, které odesílá příchozí poštu do vašeho Workeru.
- Volitelné:
EMAIL_SECRETtajný klíč, pokud chcete zabezpečené směrování odpovědí.
Nastavení domény
- Přihlaste se do Cloudflare Dashboard ↗.
- Přejděte na Compute & AI > Email Service.
- Vyberte Onboard Domain a vyberte doménu.
- Přidejte záznamy DNS (SPF a DKIM) pro autorizaci odesílání.
Změny DNS se u domén využívajících Cloudflare DNS obvykle projeví do 5-15 minut, ale globální rozšíření může trvat až 24 hodin.
Konfigurace Wrangleru
Přidejte e-mailovou vazbu do svého Workeru:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"send_email": [
{
"name": "EMAIL",
"remote": true
}
]
}[[send_email]]
name = "EMAIL"
remote = true remote = true možnost umožňuje volat skutečné Email Service API během lokálního vývoje s wrangler dev.
Rychlý start
import { Agent, callable, routeAgentEmail } from "agents";
import { createAddressBasedEmailResolver } from "agents/email";
import PostalMime from "postal-mime";
export class EmailAgent extends Agent {
@callable()
async sendWelcomeEmail(to) {
await this.sendEmail({
binding: this.env.EMAIL,
to,
from: "[email protected]",
replyTo: "[email protected]",
subject: "Welcome to our service",
text: "Thanks for signing up. Reply to this email if you need help.",
});
}
async onEmail(email) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log("Received email from:", email.from);
console.log("Subject:", parsed.subject);
await this.replyToEmail(email, {
fromName: "Support Agent",
body: "Thanks for your email! We received it.",
});
}
}
export default {
async email(message, env) {
await routeAgentEmail(message, env, {
resolver: createAddressBasedEmailResolver("EmailAgent"),
});
},
};import { Agent, callable, routeAgentEmail } from "agents";
import { createAddressBasedEmailResolver, type AgentEmail } from "agents/email";
import PostalMime from "postal-mime";
export class EmailAgent extends Agent {
@callable()
async sendWelcomeEmail(to: string) {
await this.sendEmail({
binding: this.env.EMAIL,
to,
from: "[email protected]",
replyTo: "[email protected]",
subject: "Welcome to our service",
text: "Thanks for signing up. Reply to this email if you need help.",
});
}
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log("Received email from:", email.from);
console.log("Subject:", parsed.subject);
await this.replyToEmail(email, {
fromName: "Support Agent",
body: "Thanks for your email! We received it.",
});
}
}
export default {
async email(message, env) {
await routeAgentEmail(message, env, {
resolver: createAddressBasedEmailResolver("EmailAgent"),
});
},
} satisfies ExportedHandler<Env>;Odesílání odchozích e-mailů
Použití sendEmail()
sendEmail() odesílá odchozí e-maily prostřednictvím send_email vazbu, kterou předáte explicitně. Automaticky vloží hlavičky pro směrování agenta (X-Agent-Name, X-Agent-ID) do každé zprávy a volitelně je podepíše pomocí HMAC-SHA256, aby bylo možné odpovědi směrovat zpět ke stejné instanci agenta.
class MyAgent extends Agent {
@callable()
async sendReceipt(to, orderId) {
const result = await this.sendEmail({
binding: this.env.EMAIL,
to,
from: { email: "[email protected]", name: "Billing Bot" },
replyTo: "[email protected]",
subject: `Receipt for order ${orderId}`,
text: `Your receipt for order ${orderId} is ready.`,
secret: this.env.EMAIL_SECRET,
});
return result.messageId;
}
}class MyAgent extends Agent {
@callable()
async sendReceipt(to: string, orderId: string) {
const result = await this.sendEmail({
binding: this.env.EMAIL,
to,
from: { email: "[email protected]", name: "Billing Bot" },
replyTo: "[email protected]",
subject: `Receipt for order ${orderId}`,
text: `Your receipt for order ${orderId} is ready.`,
secret: this.env.EMAIL_SECRET,
});
return result.messageId;
}
}Když secret je zadán, agent podepíše směrovací hlavičky, aby odpovědi ověřené createSecureReplyEmailResolver route směruje zpět ke stejné instanci agenta.
Nastavte replyTo do schránky, která směruje zpět na váš Worker, pokud chcete, aby příjemci pokračovali v konverzaci se stejným agentem.
Směrování příchozí pošty
Resolvery určují, která instance Agenta přijme příchozí e-mail. Vyberte resolver, který odpovídá vašemu případu užití.
Pro základní odesílání a přijímání přes Email Service createAddressBasedEmailResolver() stačí. Níže uvedený resolver zabezpečené odpovědi je volitelný a specifický pro podepisování odpovědí v Agents SDK, není to požadavek samotné služby Email Service.
createAddressBasedEmailResolver
Doporučeno pro příchozí poštu. Směruje e-maily podle adresy příjemce.
import { createAddressBasedEmailResolver } from "agents/email";
const resolver = createAddressBasedEmailResolver("EmailAgent");import { createAddressBasedEmailResolver } from "agents/email";
const resolver = createAddressBasedEmailResolver("EmailAgent");Logika směrování:
| Adresa příjemce | Agent Name | Agent ID |
|---|---|---|
[email protected] |
EmailAgent (výchozí) |
support |
[email protected] |
EmailAgent (výchozí) |
sales |
[email protected] |
NotificationAgent |
user123 |
Formát sub-adresy (agent+id@domain) umožňuje směrovat z jedné e-mailové domény na různé namespace a instance agentů.
createSecureReplyEmailResolver
Pro toky odpovědí s ověřením podpisu. Ověřuje, že příchozí e-maily jsou skutečné odpovědi na vaše odchozí e-maily, což útočníkům brání směrovat e-maily na libovolné instance agentů.
import { createSecureReplyEmailResolver } from "agents/email";
const resolver = createSecureReplyEmailResolver(env.EMAIL_SECRET);import { createSecureReplyEmailResolver } from "agents/email";
const resolver = createSecureReplyEmailResolver(env.EMAIL_SECRET);Když váš agent odešle e-mail s replyToEmail() nebo sendEmail() a secret, podepíše směrovací hlavičky časovým razítkem. Když přijde odpověď, tento resolver před směrováním ověří podpis a zkontroluje, že nevypršela platnost.
Možnosti:
const resolver = createSecureReplyEmailResolver(env.EMAIL_SECRET, {
// Maximum age of signature in seconds (default: 30 days)
maxAge: 7 * 24 * 60 * 60, // 7 days
// Callback for logging/debugging signature failures
onInvalidSignature: (email, reason) => {
console.warn(`Invalid signature from ${email.from}: ${reason}`);
// reason can be: "missing_headers", "expired", "invalid", "malformed_timestamp"
},
});const resolver = createSecureReplyEmailResolver(env.EMAIL_SECRET, {
// Maximum age of signature in seconds (default: 30 days)
maxAge: 7 * 24 * 60 * 60, // 7 days
// Callback for logging/debugging signature failures
onInvalidSignature: (email, reason) => {
console.warn(`Invalid signature from ${email.from}: ${reason}`);
// reason can be: "missing_headers", "expired", "invalid", "malformed_timestamp"
},
});Kdy použít: Pokud váš agent zahajuje e-mailové konverzace a potřebujete odpovědi bezpečně směrovat zpět ke stejné instanci agenta.
createCatchAllEmailResolver
Pro směrování na jednu instanci. Směruje všechny e-maily na konkrétní instanci agenta bez ohledu na adresu příjemce.
import { createCatchAllEmailResolver } from "agents/email";
const resolver = createCatchAllEmailResolver("EmailAgent", "default");import { createCatchAllEmailResolver } from "agents/email";
const resolver = createCatchAllEmailResolver("EmailAgent", "default");Kdy použít: Když máte jedinou instanci agenta, která zpracovává všechny e-maily (například sdílenou schránku).
Kombinace resolverů
Resolvery můžete kombinovat pro zpracování různých scénářů:
export default {
async email(message, env) {
const secureReplyResolver = createSecureReplyEmailResolver(
env.EMAIL_SECRET,
);
const addressResolver = createAddressBasedEmailResolver("EmailAgent");
await routeAgentEmail(message, env, {
resolver: async (email, env) => {
// First, check if this is a signed reply
const replyRouting = await secureReplyResolver(email, env);
if (replyRouting) return replyRouting;
// Otherwise, route based on recipient address
return addressResolver(email, env);
},
// Handle emails that do not match any routing rule
onNoRoute: (email) => {
console.warn(`No route found for email from ${email.from}`);
email.setReject("Unknown recipient");
},
});
},
};export default {
async email(message, env) {
const secureReplyResolver = createSecureReplyEmailResolver(
env.EMAIL_SECRET,
);
const addressResolver = createAddressBasedEmailResolver("EmailAgent");
await routeAgentEmail(message, env, {
resolver: async (email, env) => {
// First, check if this is a signed reply
const replyRouting = await secureReplyResolver(email, env);
if (replyRouting) return replyRouting;
// Otherwise, route based on recipient address
return addressResolver(email, env);
},
// Handle emails that do not match any routing rule
onNoRoute: (email) => {
console.warn(`No route found for email from ${email.from}`);
email.setReject("Unknown recipient");
},
});
},
} satisfies ExportedHandler<Env>;Zpracování e-mailů ve vašem agentovi
AgentEmail rozhraní
Když u agenta onEmail metoda je zavolána, obdrží AgentEmail objekt:
type AgentEmail = {
from: string; // Sender's email address
to: string; // Recipient's email address
headers: Headers; // Email headers (subject, message-id, etc.)
rawSize: number; // Size of the raw email in bytes
getRaw(): Promise<Uint8Array>; // Get the full raw email content
reply(options): Promise<void>; // Send a reply
forward(rcptTo, headers?): Promise<void>; // Forward the email
setReject(reason): void; // Reject the email with a reason
};Parsování obsahu e-mailu
Použijte knihovnu, jako je postal-mime ↗ k parsování surového e-mailu:
import PostalMime from "postal-mime";
class MyAgent extends Agent {
async onEmail(email) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log("Subject:", parsed.subject);
console.log("Text body:", parsed.text);
console.log("HTML body:", parsed.html);
console.log("Attachments:", parsed.attachments);
}
}import PostalMime from "postal-mime";
class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log("Subject:", parsed.subject);
console.log("Text body:", parsed.text);
console.log("HTML body:", parsed.html);
console.log("Attachments:", parsed.attachments);
}
}Rozpoznávání e-mailů s automatickou odpovědí
Použijte isAutoReplyEmail() k detekci automatických odpovědí e-mailem a zamezení e-mailovým smyčkám:
import { isAutoReplyEmail } from "agents/email";
import PostalMime from "postal-mime";
class MyAgent extends Agent {
async onEmail(email) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
// Detect auto-reply emails to avoid sending duplicate responses
if (isAutoReplyEmail(parsed.headers)) {
console.log("Skipping auto-reply email");
return;
}
// Process the email...
}
}import { isAutoReplyEmail } from "agents/email";
import PostalMime from "postal-mime";
class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
// Detect auto-reply emails to avoid sending duplicate responses
if (isAutoReplyEmail(parsed.headers)) {
console.log("Skipping auto-reply email");
return;
}
// Process the email...
}
}Tím se kontroluje přítomnost standardních hlaviček RFC 3834 (Auto-Submitted, X-Auto-Response-Suppress, Precedence) které signalizují, že e-mail je automatickou odpovědí.
Odpovídání na e-maily
Použijte this.replyToEmail() k odeslání odpovědi prostřednictvím kanálu odpovědí příchozího e-mailu:
class MyAgent extends Agent {
async onEmail(email) {
await this.replyToEmail(email, {
fromName: "Support Bot", // Display name for the sender
subject: "Re: Your inquiry", // Optional, defaults to "Re: "
body: "Thanks for contacting us!", // Email body
contentType: "text/plain", // Optional, defaults to "text/plain"
headers: {
// Optional custom headers
"X-Custom-Header": "value",
},
secret: this.env.EMAIL_SECRET, // Optional, signs headers for secure reply routing
});
}
}class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
await this.replyToEmail(email, {
fromName: "Support Bot", // Display name for the sender
subject: "Re: Your inquiry", // Optional, defaults to "Re: "
body: "Thanks for contacting us!", // Email body
contentType: "text/plain", // Optional, defaults to "text/plain"
headers: {
// Optional custom headers
"X-Custom-Header": "value",
},
secret: this.env.EMAIL_SECRET, // Optional, signs headers for secure reply routing
});
}
}Odložené odpovědi
replyToEmail() vyžaduje živé AgentEmail objekt, takže funguje pouze uvnitř onEmail(). Pokud potřebujete odpovědět později, například z naplánované úlohy, z volatelné metody nebo po schválení s lidským zásahem, uložte údaje o odesílateli do stavu a použijte sendEmail():
class MyAgent extends Agent {
async onEmail(email) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
this.setState({
...this.state,
pendingReply: {
to: email.from,
messageId: parsed.messageId,
subject: parsed.subject,
},
});
}
@callable()
async sendDelayedReply(body) {
const { pendingReply } = this.state;
if (!pendingReply) return;
await this.sendEmail({
binding: this.env.EMAIL,
to: pendingReply.to,
from: "[email protected]",
subject: `Re: ${pendingReply.subject}`,
text: body,
inReplyTo: pendingReply.messageId,
secret: this.env.EMAIL_SECRET,
});
}
}class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
this.setState({
...this.state,
pendingReply: {
to: email.from,
messageId: parsed.messageId,
subject: parsed.subject,
},
});
}
@callable()
async sendDelayedReply(body: string) {
const { pendingReply } = this.state;
if (!pendingReply) return;
await this.sendEmail({
binding: this.env.EMAIL,
to: pendingReply.to,
from: "[email protected]",
subject: `Re: ${pendingReply.subject}`,
text: body,
inReplyTo: pendingReply.messageId,
secret: this.env.EMAIL_SECRET,
});
}
} inReplyTo pole nastavuje In-Reply-To hlavička, aby e-mailoví klienti správně seřadili odpověď do vlákna. secret podepíše hlavičky směrování agenta, aby se navazující odpovědi směrovaly zpět k této instanci agenta prostřednictvím createSecureReplyEmailResolver.
Předávání e-mailů
class MyAgent extends Agent {
async onEmail(email) {
await email.forward("[email protected]");
}
}class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
await email.forward("[email protected]");
}
}Odmítání e-mailů
class MyAgent extends Agent {
async onEmail(email) {
if (isSpam(email)) {
email.setReject("Message rejected as spam");
return;
}
// Process the email...
}
}class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
if (isSpam(email)) {
email.setReject("Message rejected as spam");
return;
}
// Process the email...
}
}Zpracování chyb
Při odesílání e-mailů přes sendEmail() nebo replyToEmail(), ošetřete tyto běžné chyby:
class MyAgent extends Agent {
async onEmail(email) {
try {
await this.replyToEmail(email, {
fromName: "Support Bot",
body: "Thanks for your email!",
});
} catch (error) {
switch (error.code) {
case "E_SENDER_NOT_VERIFIED":
console.error("Sender domain not verified. Verify in dashboard.");
break;
case "E_RATE_LIMIT_EXCEEDED":
console.error("Rate limit exceeded. Back off and retry.");
break;
case "E_DAILY_LIMIT_EXCEEDED":
console.error("Daily sending quota reached.");
break;
case "E_CONTENT_TOO_LARGE":
console.error("Email content exceeds size limit.");
break;
default:
console.error("Email sending failed:", error.message);
}
}
}
}class MyAgent extends Agent {
async onEmail(email: AgentEmail) {
try {
await this.replyToEmail(email, {
fromName: "Support Bot",
body: "Thanks for your email!",
});
} catch (error) {
switch (error.code) {
case "E_SENDER_NOT_VERIFIED":
console.error("Sender domain not verified. Verify in dashboard.");
break;
case "E_RATE_LIMIT_EXCEEDED":
console.error("Rate limit exceeded. Back off and retry.");
break;
case "E_DAILY_LIMIT_EXCEEDED":
console.error("Daily sending quota reached.");
break;
case "E_CONTENT_TOO_LARGE":
console.error("Email content exceeds size limit.");
break;
default:
console.error("Email sending failed:", error.message);
}
}
}
}Běžné chybové kódy
| Kód chyby | Popis | Řešení |
|---|---|---|
E_SENDER_NOT_VERIFIED |
Doména nebo adresa odesílatele není ověřena | Ověřte v Cloudflare dashboardu |
E_RATE_LIMIT_EXCEEDED |
Dosažen limit rychlosti odesílání | Implementace exponenciálního odkladu opakovaných pokusů |
E_DAILY_LIMIT_EXCEEDED |
Překročena denní kvóta | Počkejte na obnovení kvóty nebo přejděte na vyšší plán |
E_CONTENT_TOO_LARGE |
E-mail překračuje limit velikosti | Omezte přílohy nebo obsah |
E_RECIPIENT_NOT_ALLOWED |
Příjemce není v seznamu povolených adres | Kontrola povolených cílových adres |
E_RECIPIENT_SUPPRESSED |
Příjemce je na seznamu potlačených adres | Odebrat ze seznamu potlačených adres |
E_VALIDATION_ERROR |
Neplatný formát e-mailu | Kontrola e-mailových adres |
E_TOO_MANY_RECIPIENTS |
Více než 50 příjemců | Rozdělení do více odeslání |
Zabezpečené směrování odpovědí
Pokud váš agent odesílá e-maily a očekává odpovědi, použijte zabezpečené směrování odpovědí, abyste útočníkům zabránili falšovat hlavičky a směrovat e-maily na libovolné instance agenta.
Jak to funguje
- Odchozí: Když zavoláte
replyToEmail()nebosendEmail()ssecret, agent podepíše směrovací hlavičky (X-Agent-Name,X-Agent-ID) pomocí HMAC-SHA256. - Příchozí:
createSecureReplyEmailResolverpřed směrováním ověří podpis. - Vynucování: Pokud byl e-mail směrován přes bezpečný resolver,
replyToEmail()vyžaduje tajný klíč (nebo explicitnínullk odhlášení).
Nastavení
-
Uložte podpisový klíč jako tajný klíč Wrangler. Neumisťujte ho do
varsnebo jej commitněte do systému správy verzí:npx wrangler secret put EMAIL_SECRET -
Použijte kombinovaný vzor resolveru:
export default { async email(message, env) { const secureReplyResolver = createSecureReplyEmailResolver( env.EMAIL_SECRET, ); const addressResolver = createAddressBasedEmailResolver("EmailAgent"); await routeAgentEmail(message, env, { resolver: async (email, env) => { const replyRouting = await secureReplyResolver(email, env); if (replyRouting) return replyRouting; return addressResolver(email, env); }, }); }, };export default { async email(message, env) { const secureReplyResolver = createSecureReplyEmailResolver( env.EMAIL_SECRET, ); const addressResolver = createAddressBasedEmailResolver("EmailAgent"); await routeAgentEmail(message, env, { resolver: async (email, env) => { const replyRouting = await secureReplyResolver(email, env); if (replyRouting) return replyRouting; return addressResolver(email, env); }, }); }, } satisfies ExportedHandler<Env>; -
Podepisujte odchozí e-maily:
class MyAgent extends Agent { async onEmail(email) { await this.replyToEmail(email, { fromName: "My Agent", body: "Thanks for your email!", secret: this.env.EMAIL_SECRET, // Signs the routing headers }); } }class MyAgent extends Agent { async onEmail(email: AgentEmail) { await this.replyToEmail(email, { fromName: "My Agent", body: "Thanks for your email!", secret: this.env.EMAIL_SECRET, // Signs the routing headers }); } }
Chování vynucování
Když je e-mail směrován přes createSecureReplyEmailResolver, replyToEmail() metoda vynucuje podepisování:
secret hodnota |
Chování |
|---|---|
"my-secret" |
Podepisuje hlavičky (bezpečné) |
undefined (vynecháno) |
Vyhazuje chybu - je nutné zadat tajný klíč nebo explicitně zvolit vyloučení |
null |
Povoleno, ale nedoporučeno: explicitně vylučuje podepisování |
Kompletní příklad
Zde je kompletní agent Email Service, který odesílá odchozí poštu a zpracovává zabezpečené odpovědi:
import { Agent, callable, routeAgentEmail } from "agents";
import {
createAddressBasedEmailResolver,
createSecureReplyEmailResolver,
} from "agents/email";
import PostalMime from "postal-mime";
export class EmailAgent extends Agent {
@callable()
async sendWelcome(to) {
return this.sendEmail({
binding: this.env.EMAIL,
to,
from: "[email protected]",
subject: "Welcome!",
text: "Thanks for signing up.",
secret: this.env.EMAIL_SECRET,
});
}
async onEmail(email) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log(`Email from ${email.from}: ${parsed.subject}`);
const emails = this.state.emails || [];
emails.push({
from: email.from,
subject: parsed.subject,
receivedAt: new Date().toISOString(),
});
this.setState({ ...this.state, emails });
await this.replyToEmail(email, {
fromName: "Support Bot",
body: `Thanks for your email! We received: "${parsed.subject}"`,
secret: this.env.EMAIL_SECRET,
});
}
}
export default {
async email(message, env) {
const secureReplyResolver = createSecureReplyEmailResolver(
env.EMAIL_SECRET,
{
maxAge: 7 * 24 * 60 * 60, // 7 days
onInvalidSignature: (email, reason) => {
console.warn(`Invalid signature from ${email.from}: ${reason}`);
},
},
);
const addressResolver = createAddressBasedEmailResolver("EmailAgent");
await routeAgentEmail(message, env, {
resolver: async (email, env) => {
const replyRouting = await secureReplyResolver(email, env);
if (replyRouting) return replyRouting;
return addressResolver(email, env);
},
onNoRoute: (email) => {
console.warn(`No route found for email from ${email.from}`);
email.setReject("Unknown recipient");
},
});
},
};import { Agent, callable, routeAgentEmail } from "agents";
import {
createAddressBasedEmailResolver,
createSecureReplyEmailResolver,
type AgentEmail,
} from "agents/email";
import PostalMime from "postal-mime";
interface Env {
EmailAgent: DurableObjectNamespace<EmailAgent>;
EMAIL: SendEmail;
EMAIL_SECRET: string;
}
export class EmailAgent extends Agent<Env> {
@callable()
async sendWelcome(to: string) {
return this.sendEmail({
binding: this.env.EMAIL,
to,
from: "[email protected]",
subject: "Welcome!",
text: "Thanks for signing up.",
secret: this.env.EMAIL_SECRET,
});
}
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log(`Email from ${email.from}: ${parsed.subject}`);
const emails = this.state.emails || [];
emails.push({
from: email.from,
subject: parsed.subject,
receivedAt: new Date().toISOString(),
});
this.setState({ ...this.state, emails });
await this.replyToEmail(email, {
fromName: "Support Bot",
body: `Thanks for your email! We received: "${parsed.subject}"`,
secret: this.env.EMAIL_SECRET,
});
}
}
export default {
async email(message, env: Env) {
const secureReplyResolver = createSecureReplyEmailResolver(
env.EMAIL_SECRET,
{
maxAge: 7 * 24 * 60 * 60, // 7 days
onInvalidSignature: (email, reason) => {
console.warn(`Invalid signature from ${email.from}: ${reason}`);
},
},
);
const addressResolver = createAddressBasedEmailResolver("EmailAgent");
await routeAgentEmail(message, env, {
resolver: async (email, env) => {
const replyRouting = await secureReplyResolver(email, env);
if (replyRouting) return replyRouting;
return addressResolver(email, env);
},
onNoRoute: (email) => {
console.warn(`No route found for email from ${email.from}`);
email.setReject("Unknown recipient");
},
});
},
} satisfies ExportedHandler<Env>;Referenční dokumentace API
EmailAddress
interface EmailAddress {
email: string;
name?: string;
}sendEmail
async sendEmail(options: {
binding: EmailSendBinding;
to: string | EmailAddress | (string | EmailAddress)[];
from: string | EmailAddress;
subject: string;
text?: string;
html?: string;
replyTo?: string | EmailAddress;
cc?: string | EmailAddress | (string | EmailAddress)[];
bcc?: string | EmailAddress | (string | EmailAddress)[];
inReplyTo?: string;
headers?: Record<string, string>;
secret?: string;
}): Promise<EmailSendResult>;Odešlete odchozí e-mail prostřednictvím vazby Email Service. Automaticky vloží X-Agent-Name a X-Agent-ID hlavičky. Když secret je zadán, podepíše hlavičky pomocí HMAC-SHA256 pro bezpečné směrování odpovědí.
| Možnost | Popis |
|---|---|
binding |
send_email vazba (například this.env.EMAIL). Povinné. |
to |
Adresa příjemce, pole adres nebo EmailAddress objekt(y) |
from |
Adresa odesílatele nebo EmailAddress objekt |
subject |
Předmět e-mailu |
text |
Tělo ve formátu prostého textu (alespoň jedno z text/html povinné) |
html |
Tělo HTML (alespoň jedno z text/html povinné) |
replyTo |
Adresa pro odpověď nebo EmailAddress objekt |
cc |
Adresa příjemce v kopii CC, pole adres nebo EmailAddress objekt(y) |
bcc |
Adresa příjemce v kopii BCC, pole adres nebo EmailAddress objekt(y) |
inReplyTo |
Message-ID pro vlákna (nastaví In-Reply-To hlavička) |
headers |
Doplňkové vlastní hlavičky (pokud dojde ke kolizi, mají přednost hlavičky agenta) |
secret |
Tajný klíč pro podepisování hlaviček směrování agenta pomocí HMAC |
routeAgentEmail
function routeAgentEmail<Env>(
email: ForwardableEmailMessage,
env: Env,
options: {
resolver: EmailResolver;
onNoRoute?: (email: ForwardableEmailMessage) => void | Promise<void>;
},
): Promise<void>;Směruje příchozí e-mail k příslušnému Agentovi na základě rozhodnutí resolveru.
| Možnost | Popis |
|---|---|
resolver |
Funkce, která určuje, kterému agentovi se má e-mail přesměrovat |
onNoRoute |
Volitelný callback, který se zavolá, pokud se nenajdou žádné informace o směrování. Použijte jej k odmítnutí e-mailu nebo k vlastnímu zpracování. Pokud není zadán, zaloguje se varování a e-mail se zahodí. |
createSecureReplyEmailResolver
function createSecureReplyEmailResolver(
secret: string,
options?: {
maxAge?: number;
onInvalidSignature?: (
email: ForwardableEmailMessage,
reason: SignatureFailureReason,
) => void;
},
): EmailResolver;
type SignatureFailureReason =
| "missing_headers"
| "expired"
| "invalid"
| "malformed_timestamp";Vytvoří resolver pro směrování e-mailových odpovědí s ověřením podpisu.
| Možnost | Popis |
|---|---|
secret |
Tajný klíč pro ověřování pomocí HMAC (musí odpovídat klíči použitému k podepsání) |
maxAge |
Maximální stáří podpisu v sekundách (výchozí: 30 dní / 2592000 sekund) |
onInvalidSignature |
Volitelný callback pro logování při selhání ověření podpisu |
signAgentHeaders
function signAgentHeaders(
secret: string,
agentName: string,
agentId: string,
): Promise<Record<string, string>>;Ručně podepsat hlavičky směrování agenta. Vrátí objekt s X-Agent-Name, X-Agent-ID, X-Agent-Sig, a X-Agent-Sig-Ts hlaviček.
Užitečné při odesílání e-mailů prostřednictvím externích služeb při zachování zabezpečeného směrování odpovědí. Podpis obsahuje časové razítko a ve výchozím nastavení bude platný 30 dní.