send-emailsend-email// ================================================================
// send-email — Supabase Edge Function
// Uses nodemailer (npm:nodemailer) — works in Supabase dashboard
// ================================================================
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
import nodemailer from "npm:nodemailer@6.9.9";
const CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
"Access-Control-Allow-Methods": "POST, OPTIONS",
};
function json(data, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: { ...CORS_HEADERS, "Content-Type": "application/json" },
});
}
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response("ok", { headers: CORS_HEADERS });
}
try {
const body = await req.json();
// ── 1. Resolve SMTP credentials ───────────────────────────
let smtp;
if (body.smtp_host) {
// Inline creds (used by test-send from settings page)
smtp = {
host : String(body.smtp_host),
port : Number(body.smtp_port) || 587,
user : String(body.smtp_user || ""),
pass : String(body.smtp_pass || ""),
fromName : String(body.smtp_from_name || ""),
fromEmail : String(body.smtp_from_email || body.smtp_user || ""),
encryption: String(body.smtp_encryption || "TLS").toUpperCase(),
};
} else if (body.account_id) {
// Load stored settings from Supabase DB
const supabase = createClient(
Deno.env.get("SUPABASE_URL"),
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")
);
const { data, error } = await supabase
.from("email_settings")
.select("*")
.eq("account_id", body.account_id)
.single();
if (error || !data) {
return json({ ok: false, error: "No SMTP settings found. Configure in App Settings → Email Settings." });
}
if (!data.smtp_enabled) {
return json({ ok: false, error: "Email sending is disabled. Enable it in Email Settings." });
}
smtp = {
host : String(data.smtp_host || ""),
port : Number(data.smtp_port) || 587,
user : String(data.smtp_user || ""),
pass : String(data.smtp_pass || ""),
fromName : String(data.smtp_from_name || ""),
fromEmail : String(data.smtp_from_email || data.smtp_user || ""),
encryption: String(data.smtp_encryption || "TLS").toUpperCase(),
};
} else {
return json({ ok: false, error: "Provide smtp_host/user/pass directly, or account_id." });
}
// ── 2. Validate ──────────────────────────────────────────
if (!smtp.host || !smtp.user) {
return json({ ok: false, error: "SMTP host and username are required." });
}
if (!body.to || !body.subject) {
return json({ ok: false, error: "'to' and 'subject' are required." });
}
// ── 3. Send via nodemailer ───────────────────────────────
const useSSL = smtp.encryption === "SSL";
const transport = nodemailer.createTransport({
host : smtp.host,
port : smtp.port,
secure: useSSL,
auth : { user: smtp.user, pass: smtp.pass },
tls : { rejectUnauthorized: false },
});
const fromAddr = smtp.fromEmail || smtp.user;
const fromFull = smtp.fromName ? `"${smtp.fromName}" <${fromAddr}>` : fromAddr;
const isHtml = body.is_html !== false;
const msg = {
from : fromFull,
to : body.to,
subject: body.subject,
...(body.cc ? { cc: body.cc } : {}),
...(isHtml ? { html: body.body } : { text: body.body }),
};
const info = await transport.sendMail(msg);
console.log(`[send-email] ✓ to=${body.to} via=${smtp.host} id=${info.messageId}`);
return json({ ok: true, messageId: info.messageId });
} catch (err) {
const msg = err?.message || String(err);
console.error("[send-email] ✗", msg);
return json({ ok: false, error: msg }, 500);
}
});
https://vjdxsvxznkeiorpphbkw.supabase.co/functions/v1/send-email
Every Send Email node in your flows will now call this function automatically. The function reads your SMTP credentials securely from Supabase — they're never sent to the browser.
macOS / Linux:
brew install supabase/tap/supabase
Windows (Scoop):
scoop bucket add supabase https://github.com/supabase/scoop-bucket.git scoop install supabase
supabase login supabase link --project-ref vjdxsvxznkeiorpphbkw
supabase functions deploy send-email --no-verify-jwt
Use the test button on the Dashboard tab to verify everything is working.