Email Settings Supabase Functions
Deploy Email Edge Function
One-time setup. Once deployed, all Send Email flow nodes and the test button in Email Settings will send real emails through your SMTP server — entirely server-side, no browser limitations.
Dashboard (Browser) RECOMMENDED
CLI
1
Open Edge Functions in Supabase Dashboard
No install required — runs entirely in your browser
Open Supabase → Edge Functions
You'll land on the Edge Functions page for your project. Click the New Function button (top right).
2
Name the function send-email
Exact name matters — the app calls this URL
1
In the Function name field type exactly: send-email
2
Make sure Verify JWT is OFF (toggle it off) — the app passes the anon key via Authorization header instead.
3
Click Create function — the inline code editor opens.
3
Paste the function code
Copy the entire block below and replace everything in the editor
// ================================================================
//  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);
  }
});
4
Click Deploy
Takes about 30–60 seconds
1
Click the Deploy button in the top right of the editor.
2
Wait for the green "Deployed" status indicator to appear.
3
Your function URL will be:
https://vjdxsvxznkeiorpphbkw.supabase.co/functions/v1/send-email
Test it right here
Send a live test email using your stored SMTP settings

All done!

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.

Back to Email Settings Back to App
1
Install Supabase CLI
One-time install

macOS / Linux:

brew install supabase/tap/supabase

Windows (Scoop):

scoop bucket add supabase https://github.com/supabase/scoop-bucket.git
scoop install supabase
2
Login & link project
Run from your project root folder
3
Deploy
The function file is already in your project
supabase functions deploy send-email --no-verify-jwt

Deployed via CLI!

Use the test button on the Dashboard tab to verify everything is working.