Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-04-24 03:34:02 +00:00
co-authored by renee-png
parent 0be9d7a595
commit 7af969617e
+57 -4
View File
@@ -5,6 +5,7 @@ import { createFileRoute } from "@tanstack/react-router";
import { supabaseAdmin } from "@/integrations/supabase/client.server";
import { ImapFlow } from "imapflow";
import { simpleParser } from "mailparser";
import { matchAndUpdateEmails } from "@/lib/email-matching.server";
const MAX_MESSAGES_PER_RUN = 50;
@@ -82,6 +83,51 @@ export const Route = createFileRoute("/hooks/poll-imap")({
: null;
const attachments = parsed.attachments ?? [];
// Upload attachments to storage; collect metadata.
const attachmentMeta: Array<{
filename: string;
mime_type: string;
size_bytes: number;
storage_path: string;
}> = [];
for (let i = 0; i < attachments.length; i++) {
const att = attachments[i];
const filename =
att.filename || `attachment-${i + 1}.bin`;
const safeName = filename.replace(/[^\w.\-]+/g, "_");
const path = `${msg.uid}/${Date.now()}-${i}-${safeName}`;
try {
const { error: upErr } = await supabaseAdmin.storage
.from("email-attachments")
.upload(path, att.content as Buffer, {
contentType: att.contentType || "application/octet-stream",
upsert: true,
});
if (upErr) {
console.error("Attachment upload failed", filename, upErr.message);
continue;
}
attachmentMeta.push({
filename,
mime_type: att.contentType || "application/octet-stream",
size_bytes: att.size ?? (att.content as Buffer)?.length ?? 0,
storage_path: path,
});
} catch (e) {
console.error("Attachment store error", filename, e);
}
}
// Threading headers
const inReplyTo =
(parsed.inReplyTo as string | undefined) ?? null;
const refsRaw = (parsed.references as string | string[] | undefined) ?? [];
const references = Array.isArray(refsRaw)
? refsRaw
: refsRaw
? [refsRaw]
: [];
const insertRow = {
message_id: parsed.messageId ?? null,
imap_uid: msg.uid,
@@ -94,20 +140,27 @@ export const Route = createFileRoute("/hooks/poll-imap")({
body_text: text,
body_html: parsed.html || null,
snippet,
has_attachments: attachments.length > 0,
attachment_count: attachments.length,
has_attachments: attachmentMeta.length > 0,
attachment_count: attachmentMeta.length,
attachments: attachmentMeta,
in_reply_to: inReplyTo,
email_references: references,
raw_size_bytes: msg.size ?? null,
};
// Upsert by message_id to avoid duplicates if mailbox is re-polled
const { error: insErr } = await supabaseAdmin
const { data: insertedRows, error: insErr } = await supabaseAdmin
.from("incoming_emails")
.upsert(insertRow, { onConflict: "message_id", ignoreDuplicates: true });
.upsert(insertRow, { onConflict: "message_id", ignoreDuplicates: true })
.select("id");
if (insErr && !insErr.message.includes("duplicate")) {
console.error("Insert failed for uid", msg.uid, insErr.message);
} else {
imported++;
if (insertedRows && insertedRows.length > 0) {
newEmailIds.push(insertedRows[0].id);
}
}
if (msg.uid > highestUid) highestUid = msg.uid;