send-test-email.mjs
1 #!/usr/bin/env node 2 /** 3 * One-shot script: send a representative sample outreach email to deliverability 4 * test addresses (mail-tester.com, Email on Acid, etc.) 5 * 6 * Usage: 7 * node scripts/send-test-email.mjs 8 * node scripts/send-test-email.mjs recipient@example.com 9 */ 10 11 import '../src/utils/load-env.js'; 12 13 const {RESEND_API_KEY} = process.env; 14 if (!RESEND_API_KEY) { console.error('RESEND_API_KEY not set'); process.exit(1); } 15 16 if (!process.env.PERSONA_NAME) throw new Error('PERSONA_NAME env var required'); 17 if (!process.env.BRAND_NAME) throw new Error('BRAND_NAME env var required'); 18 if (!process.env.BRAND_DOMAIN) throw new Error('BRAND_DOMAIN env var required'); 19 20 const SENDER_NAME = process.env.SENDER_NAME || process.env.PERSONA_NAME; 21 const SENDER_EMAIL = process.env.SENDER_EMAIL || `${process.env.PERSONA_FIRST_NAME?.toLowerCase()}@${process.env.BRAND_DOMAIN}`; 22 const SIGNATURE = (process.env.EMAIL_SIGNATURE || `Best regards,\n${SENDER_NAME}\n${process.env.BRAND_NAME}`).replace(/\\n/g, '\n'); 23 const PHYSICAL_ADDR = process.env.CAN_SPAM_PHYSICAL_ADDRESS || ''; 24 const UNSUBSCRIBE_URL = `https://${process.env.BRAND_DOMAIN}/unsubscribe?id=test&token=abc123test`; 25 26 const SUBJECT = "your electrician website isn't converting visitors"; 27 28 const BODY = `Hi there, 29 30 Your tarelectric.ca website scored 51.4/100 (D grade). We've analysed 43,000+ local business sites, and your homepage lacks clear trust signals and a compelling unique selling proposition. 31 32 Nothing is broken, but you could be missing out on up to 22-32% more leads just from the way your homepage and call-to-action are structured above the fold. 33 34 I do simple Website Conversion Audits that break this down and show exactly what to change for fast lead increases. It's a one-time service — 24-hour turnaround — and the audit is yours to keep. 35 36 Would you be interested in seeing what I found?`; 37 38 function buildHtml(body, sig, unsubUrl, physAddr, senderName) { 39 const toHtml = t => t.split('\n') 40 .map(l => l.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" style="color:#0066cc;">$1</a>')) 41 .join('<br>'); 42 const physHtml = physAddr 43 ? `<div style="margin-top:10px;font-size:11px;color:#999;">${physAddr}</div>` : ''; 44 return `<!DOCTYPE html> 45 <html> 46 <head> 47 <meta charset="utf-8"> 48 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 49 <title>${senderName} — website review</title> 50 </head> 51 <body style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;line-height:1.6;color:#333;max-width:600px;margin:0 auto;padding:20px;"> 52 <div style="white-space:pre-wrap;">${toHtml(body)}</div> 53 <div style="margin-top:20px;padding-top:20px;border-top:1px solid #eee;white-space:pre-wrap;">${toHtml(sig)}${physHtml}</div> 54 <div style="margin-top:30px;padding-top:20px;border-top:1px solid #eee;font-size:12px;color:#666;"> 55 <p>You received this email because ${senderName} found your business online and believes our web optimisation services may be relevant to you. This is a one-time outreach, not a mailing list.</p> 56 <p>If you'd prefer not to receive emails from us, <a href="${unsubUrl}" style="color:#666;">unsubscribe here</a>.</p> 57 </div> 58 </body> 59 </html>`.trim(); 60 } 61 62 const html = buildHtml(BODY, SIGNATURE, UNSUBSCRIBE_URL, PHYSICAL_ADDR, SENDER_NAME); 63 const text = `${BODY}\n\n${SIGNATURE}${PHYSICAL_ADDR ? `\n\n${ PHYSICAL_ADDR}` : ''}\n\n---\nYou received this email because ${SENDER_NAME} found your business online.\nTo unsubscribe: ${UNSUBSCRIBE_URL}`; 64 65 const targets = process.argv[2] 66 ? [process.argv[2]] 67 : [ 68 'test-vk2xyxbp1@srv1.mail-tester.com', 69 'mailteser+default@precheck.emailonacid.com', 70 ]; 71 72 for (const to of targets) { 73 process.stdout.write(`Sending to ${to}... `); 74 const res = await fetch('https://api.resend.com/emails', { 75 method: 'POST', 76 headers: { 77 Authorization: `Bearer ${RESEND_API_KEY}`, 78 'Content-Type': 'application/json', 79 'User-Agent': '333Method/1.0', 80 }, 81 body: JSON.stringify({ 82 from: `${SENDER_NAME} <${SENDER_EMAIL}>`, 83 to, 84 subject: SUBJECT, 85 html, 86 text, 87 headers: { 88 'List-Unsubscribe': `<${UNSUBSCRIBE_URL}>`, 89 'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click', 90 }, 91 }), 92 }); 93 const data = await res.json(); 94 if (res.ok) { 95 console.log(`✓ Resend ID: ${data.id}`); 96 } else { 97 console.error(`✗ ${res.status}: ${JSON.stringify(data)}`); 98 } 99 }