Email System Fixes: - Fix email sending after payment: handle-order-paid now calls send-notification instead of send-email-v2 directly, properly processing template variables - Fix order_created email timing: sent immediately after order creation, before payment QR code generation - Update email templates to use short order ID (8 chars) instead of full UUID - Add working "Akses Sekarang" buttons to payment_success and access_granted emails - Add platform_url column to platform_settings for email links OTP Verification Flow: - Create dedicated /confirm-otp page for users who close registration modal - Add link in checkout modal and email to dedicated OTP page - Update OTP email template with better copywriting and dedicated page link - Fix send-auth-otp to fetch platform settings for dynamic brand_name and platform_url - Auto-login users after OTP verification in checkout flow Admin Features: - Add delete user functionality with cascade deletion of all related data - Update IntegrasiTab to read/write email settings from platform_settings only - Add test email template for email configuration testing Cleanup: - Remove obsolete send-consultation-reminder and send-test-email functions - Update send-email-v2 to read email config from platform_settings - Remove footer links (Ubah Preferensi/Unsubscribe) from email templates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
131 lines
4.3 KiB
TypeScript
131 lines
4.3 KiB
TypeScript
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
|
|
|
|
const corsHeaders = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
|
|
};
|
|
|
|
interface EmailRequest {
|
|
recipient: string;
|
|
subject: string;
|
|
content: string;
|
|
}
|
|
|
|
// Send via Mailketing API
|
|
async function sendViaMailketing(
|
|
request: EmailRequest,
|
|
apiToken: string,
|
|
fromName: string,
|
|
fromEmail: string
|
|
): Promise<{ success: boolean; message: string }> {
|
|
const { recipient, subject, content } = request;
|
|
|
|
// Build form-encoded body (http_build_query format)
|
|
const params = new URLSearchParams();
|
|
params.append('api_token', apiToken);
|
|
params.append('from_name', fromName);
|
|
params.append('from_email', fromEmail);
|
|
params.append('recipient', recipient);
|
|
params.append('subject', subject);
|
|
params.append('content', content);
|
|
|
|
console.log(`Sending email via Mailketing to ${recipient}`);
|
|
|
|
const response = await fetch('https://api.mailketing.co.id/api/v1/send', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: params.toString(),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
console.error('Mailketing API error:', response.status, errorText);
|
|
throw new Error(`Mailketing API error: ${response.status} ${errorText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
console.log('Mailketing API response:', result);
|
|
|
|
return {
|
|
success: true,
|
|
message: result.response || 'Email sent successfully via Mailketing'
|
|
};
|
|
}
|
|
|
|
serve(async (req: Request): Promise<Response> => {
|
|
if (req.method === "OPTIONS") {
|
|
return new Response(null, { headers: corsHeaders });
|
|
}
|
|
|
|
try {
|
|
// Initialize Supabase client
|
|
const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
|
|
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
|
|
const supabase = createClient(supabaseUrl, supabaseServiceKey);
|
|
|
|
// Fetch email settings from platform_settings
|
|
const { data: settings, error: settingsError } = await supabase
|
|
.from('platform_settings')
|
|
.select('*')
|
|
.single();
|
|
|
|
if (settingsError || !settings) {
|
|
console.error('Error fetching platform settings:', settingsError);
|
|
throw new Error('Failed to fetch email configuration from platform_settings');
|
|
}
|
|
|
|
const apiToken = settings.integration_email_api_token;
|
|
const fromName = settings.integration_email_from_name || settings.brand_name;
|
|
const fromEmail = settings.integration_email_from_email;
|
|
|
|
if (!apiToken || !fromEmail) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, message: "Email not configured. Please set API token and from email in platform settings." }),
|
|
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
const body: EmailRequest = await req.json();
|
|
|
|
// Validate required fields
|
|
if (!body.recipient || !body.subject || !body.content) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, message: "Missing required fields: recipient, subject, content" }),
|
|
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
// Basic email validation
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
if (!emailRegex.test(body.recipient) || !emailRegex.test(fromEmail)) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, message: "Invalid email format" }),
|
|
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
console.log(`Attempting to send email to: ${body.recipient}`);
|
|
console.log(`From: ${fromName} <${fromEmail}>`);
|
|
console.log(`Subject: ${body.subject}`);
|
|
|
|
const result = await sendViaMailketing(body, apiToken, fromName, fromEmail);
|
|
|
|
return new Response(
|
|
JSON.stringify(result),
|
|
{ status: 200, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
|
|
} catch (error: any) {
|
|
console.error("Error sending email:", error);
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: false,
|
|
message: error.message || "Failed to send email"
|
|
}),
|
|
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
}); |