import { Hono } from "hono"; import { Env, EmailMetadata } from "../../types"; import { logger } from "../../infrastructure/logger"; import { Layout, clampText, CopyIcon, CheckIcon, FeedFormats, ExpiryBadge, NativeFeeds, } from "./ui"; import { unionNativeFeeds } from "../../domain/native-feed"; import { deleteAttachmentsForEmails, deleteKeysWithConcurrency, } from "../../application/feed-cleanup"; import { FeedRepository } from "../../infrastructure/feed-repository"; import { FeedId } from "../../domain/value-objects/feed-id"; import { feedEmailAddress, baseUrl, entryPath, } from "../../infrastructure/urls"; import { processEmailContent } from "../../infrastructure/html-processor"; import { formatBytes } from "../../domain/format"; import { EmailAddress } from "../../domain/value-objects/email-address"; import { emailsPageScript } from "../../scripts/generated/emails-page"; import emailPreviewCss from "../../styles/email-preview.css"; type AppEnv = { Bindings: Env }; export const emailsRouter = new Hono(); type CopyFieldProps = { label: string; value: string; display?: string; }; const CopyField = ({ label, value, display }: CopyFieldProps) => (
{label}
{display ?? value}
); type SenderFieldProps = { from: string; feedId: string; }; const SenderField = ({ from, feedId }: SenderFieldProps) => { const parsed = EmailAddress.parse(from); const senderEmail = parsed?.normalized ?? from.trim().toLowerCase(); const senderDomain = parsed?.domain.value ?? ""; return (
From:
{from}
); }; // ── View all emails for a feed ──────────────────────────────────────────────── emailsRouter.get("/feeds/:feedId/emails", async (c) => { const env = c.env; const repo = FeedRepository.from(env); const feedId = c.req.param("feedId"); const message = c.req.query("message"); const count = Number(c.req.query("count") || "0"); const id = FeedId.unchecked(feedId); const feedConfig = await repo.getConfig(id); const feedMetadata = await repo.getMetadata(id); if (!feedConfig || !feedMetadata) { return c.text("Feed not found", 404); } const nativeFeeds = unionNativeFeeds(feedMetadata.nativeFeeds); const emailAddress = feedEmailAddress(feedConfig.mailbox_id, env); return c.html(

{feedConfig.title} - Emails

{feedConfig.expires_at && (
)}
{feedMetadata.pendingConfirmation && (
A subscription-confirmation email was detected.
)} {nativeFeeds.length > 0 && !feedMetadata.nativeFeedDismissed && (
This newsletter publishes its own feed — subscribe to it directly from "Native feeds" above.
)}

Emails ( {feedMetadata.emails.length})

{message === "bulkDeleted" && (

Deleted {Number.isFinite(count) ? count : 0} email(s).

)} {message === "bulkDeleteNoop" && (

No emails were selected.

)} {feedMetadata.emails.length > 0 ? (
Showing {feedMetadata.emails.length} 0 selected
{feedMetadata.emails.map((email: EmailMetadata) => { const subjectDisplay = clampText(email.subject, 180); const subjectHover = clampText(email.subject, 1000); const attachmentCount = email.attachmentIds?.length ?? 0; const attachmentLabel = `${attachmentCount} attachment${ attachmentCount > 1 ? "s" : "" }`; const isConfirmation = !!email.confirmation; const sortSubject = subjectHover.toLowerCase(); const sortReceivedAt = String(email.receivedAt); const searchHaystack = clampText( email.subject, 320, ).toLowerCase(); return ( ); })}
Actions
) : (

No emails received yet. Subscribe to newsletters using the email address above.

)}
{/* Config bootstrap — injects dynamic server-side data before the static compiled script */}