Files
acmcc/supabase/functions/mailchimp-campaign/index.ts
T
2026-06-01 20:19:26 -04:00

105 lines
4.0 KiB
TypeScript

import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.0";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
Deno.serve(async (req) => {
if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
try {
const { association_id, subject, from_name, reply_to, html, send_now } = await req.json();
if (!association_id || !subject || !from_name || !reply_to || !html) {
return new Response(JSON.stringify({ success: false, error: "Missing required fields." }), {
status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
);
const { data: config, error: cfgErr } = await supabase
.from("mailchimp_configs")
.select("*")
.eq("association_id", association_id)
.maybeSingle();
if (cfgErr) throw cfgErr;
if (!config?.api_key || !config?.server_prefix || !config?.audience_id) {
return new Response(JSON.stringify({ success: false, error: "Mailchimp is not configured for this association." }), {
status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
const baseUrl = `https://${config.server_prefix}.api.mailchimp.com/3.0`;
const auth = "Basic " + btoa(`anystring:${config.api_key}`);
// 1. Create the campaign
const createRes = await fetch(`${baseUrl}/campaigns`, {
method: "POST",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({
type: "regular",
recipients: { list_id: config.audience_id },
settings: {
subject_line: subject,
title: `${subject} - ${new Date().toISOString()}`,
from_name,
reply_to,
},
}),
});
const campaign = await createRes.json();
if (!createRes.ok) {
return new Response(JSON.stringify({ success: false, error: `Create failed: ${campaign.detail || campaign.title || "Unknown"}` }), {
status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
// 2. Set the content
const contentRes = await fetch(`${baseUrl}/campaigns/${campaign.id}/content`, {
method: "PUT",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({ html }),
});
if (!contentRes.ok) {
const errBody = await contentRes.json().catch(() => ({}));
return new Response(JSON.stringify({ success: false, error: `Content failed: ${errBody.detail || "Unknown"}`, campaign_id: campaign.id }), {
status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
// 3. Optionally send immediately
if (send_now) {
const sendRes = await fetch(`${baseUrl}/campaigns/${campaign.id}/actions/send`, {
method: "POST",
headers: { Authorization: auth },
});
if (!sendRes.ok) {
const errBody = await sendRes.json().catch(() => ({}));
return new Response(JSON.stringify({
success: false,
error: `Send failed: ${errBody.detail || errBody.title || "Unknown"}. Campaign saved as draft in Mailchimp.`,
campaign_id: campaign.id,
web_id: campaign.web_id,
}), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });
}
}
return new Response(JSON.stringify({
success: true,
campaign_id: campaign.id,
web_id: campaign.web_id,
sent: !!send_now,
recipient_count: campaign.recipients?.recipient_count ?? null,
}), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
} catch (e: any) {
return new Response(JSON.stringify({ success: false, error: e.message || String(e) }), {
status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
});