Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-04-17 22:53:27 +00:00
co-authored by renee-png
parent be07ab2fa3
commit c71f7dbd87
3 changed files with 398 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
// Send an email via the firm's configured SMTP server.
// Uses denomailer (SMTP client for Deno).
import { SMTPClient } from "https://deno.land/x/denomailer@1.6.0/mod.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.49.4";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers":
"authorization, x-client-info, apikey, content-type",
};
interface SendBody {
to: string | string[];
subject: string;
html?: string;
text?: string;
cc?: string | string[];
bcc?: string | string[];
replyTo?: string;
test?: boolean;
}
Deno.serve(async (req) => {
if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
try {
const authHeader = req.headers.get("Authorization");
if (!authHeader) {
return json({ error: "Missing authorization" }, 401);
}
const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
const anonKey = Deno.env.get("SUPABASE_ANON_KEY")!;
const serviceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
// Verify caller is authenticated
const userClient = createClient(supabaseUrl, anonKey, {
global: { headers: { Authorization: authHeader } },
});
const { data: userData, error: userErr } = await userClient.auth.getUser();
if (userErr || !userData.user) return json({ error: "Unauthorized" }, 401);
const admin = createClient(supabaseUrl, serviceKey);
// Load latest enabled SMTP settings
const { data: settings, error: setErr } = await admin
.from("smtp_settings")
.select("*")
.eq("enabled", true)
.order("updated_at", { ascending: false })
.limit(1)
.maybeSingle();
if (setErr) return json({ error: setErr.message }, 500);
if (!settings) return json({ error: "No SMTP settings configured" }, 400);
const password = Deno.env.get("SMTP_PASSWORD") ?? "";
if (!password) return json({ error: "SMTP_PASSWORD secret not set" }, 400);
const body = (await req.json()) as SendBody;
if (!body.to || !body.subject) {
return json({ error: "to and subject are required" }, 400);
}
const client = new SMTPClient({
connection: {
hostname: settings.host,
port: settings.port,
tls: !!settings.secure,
auth: settings.username
? { username: settings.username, password }
: undefined,
},
});
const fromAddr = settings.from_name
? `${settings.from_name} <${settings.from_email}>`
: settings.from_email;
await client.send({
from: fromAddr,
to: body.to,
cc: body.cc,
bcc: body.bcc,
replyTo: body.replyTo ?? settings.reply_to ?? undefined,
subject: body.subject,
content: body.text ?? "auto",
html: body.html,
});
await client.close();
return json({ ok: true });
} catch (e) {
console.error("send-smtp-email error", e);
return json({ error: e instanceof Error ? e.message : String(e) }, 500);
}
});
function json(data: unknown, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}