mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-21 06:13:48 +00:00
refactor: extract ForwardEmail adapter to src/lib/forwardemail.ts
Mirrors the same pattern as cloudflare-email.ts — each provider has its own adapter that translates provider-specific input into ProcessEmailInput and delegates to processEmail(). inbound.ts is now a thin HTTP handler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
import { EmailParser } from "../utils/email-parser";
|
||||||
|
import { Env } from "../types";
|
||||||
|
import { processEmail } from "./email-processor";
|
||||||
|
|
||||||
|
export interface ForwardEmailPayload {
|
||||||
|
recipients?: string[];
|
||||||
|
from?: {
|
||||||
|
value?: Array<{ address?: string; name?: string }>;
|
||||||
|
text?: string;
|
||||||
|
html?: string;
|
||||||
|
};
|
||||||
|
subject?: string;
|
||||||
|
text?: string;
|
||||||
|
html?: string;
|
||||||
|
date?: string;
|
||||||
|
messageId?: string;
|
||||||
|
headerLines?: Array<{ key: string; line: string }>;
|
||||||
|
headers?: string;
|
||||||
|
raw?: string;
|
||||||
|
attachments?: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeEmail(value: string): string {
|
||||||
|
return value.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSenderAddresses(payload: ForwardEmailPayload): string[] {
|
||||||
|
const valueEntries = payload.from?.value || [];
|
||||||
|
const structuredAddresses = valueEntries
|
||||||
|
.map((entry) => entry.address || "")
|
||||||
|
.map(normalizeEmail)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (structuredAddresses.length > 0) {
|
||||||
|
return Array.from(new Set(structuredAddresses));
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromText = payload.from?.text || "";
|
||||||
|
const matches =
|
||||||
|
fromText.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi) || [];
|
||||||
|
return Array.from(new Set(matches.map(normalizeEmail)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handleForwardEmail(
|
||||||
|
payload: ForwardEmailPayload,
|
||||||
|
env: Env,
|
||||||
|
): Promise<Response> {
|
||||||
|
const emailData = EmailParser.parseForwardEmailPayload(payload);
|
||||||
|
|
||||||
|
return processEmail(
|
||||||
|
{
|
||||||
|
toAddress: payload.recipients?.[0] || "",
|
||||||
|
from: emailData.from,
|
||||||
|
senders: extractSenderAddresses(payload),
|
||||||
|
subject: emailData.subject,
|
||||||
|
content: emailData.content,
|
||||||
|
receivedAt: emailData.receivedAt,
|
||||||
|
headers: emailData.headers,
|
||||||
|
},
|
||||||
|
env,
|
||||||
|
);
|
||||||
|
}
|
||||||
+5
-53
@@ -1,44 +1,9 @@
|
|||||||
import { Context } from "hono";
|
import { Context } from "hono";
|
||||||
import { EmailParser } from "../utils/email-parser";
|
|
||||||
import { Env } from "../types";
|
import { Env } from "../types";
|
||||||
import { processEmail } from "../lib/email-processor";
|
import {
|
||||||
|
ForwardEmailPayload,
|
||||||
interface ForwardEmailPayload {
|
handleForwardEmail,
|
||||||
recipients?: string[];
|
} from "../lib/forwardemail";
|
||||||
from?: {
|
|
||||||
value?: Array<{ address?: string; name?: string }>;
|
|
||||||
text?: string;
|
|
||||||
html?: string;
|
|
||||||
};
|
|
||||||
subject?: string;
|
|
||||||
text?: string;
|
|
||||||
html?: string;
|
|
||||||
date?: string;
|
|
||||||
messageId?: string;
|
|
||||||
headerLines?: Array<{ key: string; line: string }>;
|
|
||||||
headers?: string;
|
|
||||||
raw?: string;
|
|
||||||
attachments?: Array<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractIncomingSenderAddresses(
|
|
||||||
payload: ForwardEmailPayload,
|
|
||||||
): string[] {
|
|
||||||
const valueEntries = payload.from?.value || [];
|
|
||||||
const structuredAddresses = valueEntries
|
|
||||||
.map((entry) => entry.address || "")
|
|
||||||
.map((v) => v.trim().toLowerCase())
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
if (structuredAddresses.length > 0) {
|
|
||||||
return Array.from(new Set(structuredAddresses));
|
|
||||||
}
|
|
||||||
|
|
||||||
const fromText = payload.from?.text || "";
|
|
||||||
const matches =
|
|
||||||
fromText.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi) || [];
|
|
||||||
return Array.from(new Set(matches.map((v) => v.trim().toLowerCase())));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handle(c: Context): Promise<Response> {
|
export async function handle(c: Context): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
@@ -52,20 +17,7 @@ export async function handle(c: Context): Promise<Response> {
|
|||||||
contentType: payload.html ? "HTML" : "Text",
|
contentType: payload.html ? "HTML" : "Text",
|
||||||
});
|
});
|
||||||
|
|
||||||
const emailData = EmailParser.parseForwardEmailPayload(payload);
|
return handleForwardEmail(payload, env);
|
||||||
|
|
||||||
return processEmail(
|
|
||||||
{
|
|
||||||
toAddress: payload.recipients?.[0] || "",
|
|
||||||
from: emailData.from,
|
|
||||||
senders: extractIncomingSenderAddresses(payload),
|
|
||||||
subject: emailData.subject,
|
|
||||||
content: emailData.content,
|
|
||||||
receivedAt: emailData.receivedAt,
|
|
||||||
headers: emailData.headers,
|
|
||||||
},
|
|
||||||
env,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing email:", error);
|
console.error("Error processing email:", error);
|
||||||
return new Response("Error processing email", { status: 500 });
|
return new Response("Error processing email", { status: 500 });
|
||||||
|
|||||||
Reference in New Issue
Block a user