notamitgamer

It's my profile man, there is ...
Log | Files | Refs | README

server.js (12384B)


      1 const express = require('express');
      2 const { Resend } = require('resend');
      3 const { Webhook } = require('svix');
      4 
      5 const app = express();
      6 const port = process.env.PORT || 3000;
      7 
      8 const resend = new Resend(process.env.RESEND_API_KEY);
      9 const webhookSecret = process.env.RESEND_WEBHOOK_SECRET;
     10 
     11 app.post('/api/incoming', express.text({ type: 'application/json' }), async (req, res) => {
     12   try {
     13     const rawBody = req.body;
     14     const headers = {
     15       'svix-id': req.headers['svix-id'],
     16       'svix-timestamp': req.headers['svix-timestamp'],
     17       'svix-signature': req.headers['svix-signature'],
     18     };
     19 
     20     const wh = new Webhook(webhookSecret);
     21     let event;
     22     
     23     try {
     24       event = wh.verify(rawBody, headers);
     25     } catch (err) {
     26       console.error(err.message);
     27       return res.status(400).json({ error: 'Invalid signature' });
     28     }
     29 
     30     if (event.type !== 'email.received') {
     31       return res.status(200).json({ message: 'Not an email event' });
     32     }
     33 
     34     const emailData = event.data;
     35     const originalSender = emailData.from;
     36     const originalRecipient = emailData.to[0].toLowerCase();
     37     const subject = emailData.subject || 'No Subject';
     38 
     39     const allowedString = process.env.ALLOWED_ALIASES || '';
     40     const allowedAliases = allowedString.split(',').map(alias => alias.trim().toLowerCase());
     41 
     42     if (!allowedAliases.includes(originalRecipient)) {
     43       return res.status(200).json({ success: true, message: 'Alias ignored' });
     44     }
     45 
     46     const personalGmail = process.env.PERSONAL_GMAIL; 
     47     const forwardingAddress = process.env.FORWARDING_BOT_ADDRESS; 
     48 
     49     // Premium Adaptive Google-style HTML Template
     50     const notificationHtml = `
     51 <!DOCTYPE html>
     52 <html lang="en" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
     53 <head>
     54   <meta charset="UTF-8">
     55   <meta name="viewport" content="width=device-width, initial-scale=1.0">
     56   <meta name="color-scheme" content="light dark">
     57   <meta name="supported-color-schemes" content="light dark">
     58   <title>New Email Notification</title>
     59   
     60   <style>
     61     @import url('https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500&family=Roboto+Mono:wght@400;500&family=Roboto:wght@400;500&display=swap');
     62     
     63     body {
     64       margin: 0;
     65       padding: 0;
     66       -webkit-font-smoothing: antialiased;
     67       -moz-osx-font-smoothing: grayscale;
     68     }
     69 
     70     .btn-pill:hover {
     71       opacity: 0.9;
     72       transform: translateY(-1px);
     73       transition: all 0.2s ease;
     74     }
     75 
     76     @media (prefers-color-scheme: dark) {
     77       .bg-outer { background-color: #131314 !important; }
     78       .bg-card { background-color: #1E1F20 !important; }
     79       .bg-tint { background-color: #282A2C !important; }
     80       .text-primary { color: #E3E3E3 !important; }
     81       .text-secondary { color: #C4C7C5 !important; }
     82       .text-accent { color: #A8C7FA !important; }
     83       .border-card { border-color: #444746 !important; }
     84       .divider { background-color: #444746 !important; }
     85       .btn-pill { 
     86         background-color: #A8C7FA !important; 
     87         color: #000000 !important; 
     88       }
     89       .icon-fill { fill: #8E918F !important; }
     90     }
     91 
     92     /* Gmail Dark Mode Fixes */
     93     [data-ogsb] .bg-outer { background-color: #131314 !important; }
     94     [data-ogsb] .bg-card { background-color: #1E1F20 !important; }
     95     [data-ogsb] .bg-tint { background-color: #282A2C !important; }
     96     [data-ogsc] .text-primary { color: #E3E3E3 !important; }
     97     [data-ogsc] .text-secondary { color: #C4C7C5 !important; }
     98     [data-ogsc] .text-accent { color: #A8C7FA !important; }
     99     [data-ogsb] .border-card { border-color: #444746 !important; }
    100     [data-ogsb] .divider { background-color: #444746 !important; }
    101     [data-ogsb] .btn-pill { background-color: #A8C7FA !important; }
    102     [data-ogsc] .btn-pill { color: #000000 !important; }
    103     [data-ogsc] .icon-fill { fill: #8E918F !important; }
    104   </style>
    105 </head>
    106 
    107 <body class="bg-outer" style="margin: 0; padding: 0; background-color: #F8F9FA; font-family: 'Google Sans', Roboto, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased;">
    108 
    109   <table width="100%" border="0" cellspacing="0" cellpadding="0" class="bg-outer" style="background-color: #F8F9FA; width: 100%; height: 100%;">
    110     <tr>
    111       <td align="center" style="padding: 40px 16px;">
    112         
    113         <table border="0" cellspacing="0" cellpadding="0" class="bg-card border-card" style="background-color: #FFFFFF; border-radius: 28px; max-width: 600px; width: 100%; overflow: hidden; border: 1px solid #C4C7C5;">
    114           
    115           <tr>
    116             <td style="padding: 40px 32px 16px 32px;">
    117               <h2 class="text-primary" style="margin: 0; font-family: 'Google Sans', Roboto, sans-serif; font-size: 22px; font-weight: 500; color: #1F1F1F; letter-spacing: -0.5px;">Incoming Message</h2>
    118               <p class="text-secondary" style="margin: 8px 0 0 0; font-family: Roboto, Arial, sans-serif; font-size: 14px; font-weight: 400; color: #444746; line-height: 1.5;">A new email has been routed to your developer inbox.</p>
    119             </td>
    120           </tr>
    121 
    122           <tr>
    123             <td style="padding: 0 32px;">
    124               <div class="divider" style="height: 1px; background-color: #E3E3E3; width: 100%; margin: 16px 0;"></div>
    125             </td>
    126           </tr>
    127 
    128           <tr>
    129             <td style="padding: 16px 32px;">
    130               
    131               <div style="margin-bottom: 24px;">
    132                 <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 6px;">Sender Email ID</span>
    133                 <span class="text-primary" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-weight: 400; color: #1F1F1F; word-break: break-all; line-height: 1.4;">${originalSender}</span>
    134               </div>
    135 
    136               <div style="margin-bottom: 24px;">
    137                 <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 6px;">Subject</span>
    138                 <span class="text-primary" style="display: block; font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 18px; font-weight: 500; color: #1F1F1F; line-height: 1.4;">${subject}</span>
    139               </div>
    140 
    141               <div style="margin-bottom: 32px;">
    142                 <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px;">Email Tracking ID</span>
    143                 
    144                 <table border="0" cellspacing="0" cellpadding="0" style="width: 100%;">
    145                   <tr>
    146                     <td class="bg-tint" style="background-color: #F0F4F9; border-radius: 8px; padding: 12px 16px;">
    147                       <span class="text-secondary" style="display: block; font-family: 'Roboto Mono', monospace; font-size: 14px; font-weight: 500; color: #444746; word-break: break-all;">
    148                         ${emailData.email_id || 'N/A'}
    149                       </span>
    150                     </td>
    151                   </tr>
    152                 </table>
    153               </div>
    154               
    155             </td>
    156           </tr>
    157 
    158           <tr>
    159             <td style="padding: 8px 32px 40px 32px;">
    160               <table border="0" cellspacing="0" cellpadding="0">
    161                 <tr>
    162                   <td align="center" style="border-radius: 100px;">
    163                     <a href="https://resend.com/emails/${emailData.email_id}" target="_blank" class="btn-pill" style="display: inline-block; padding: 12px 32px; background-color: #0B57D0; font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 14px; font-weight: 500; color: #FFFFFF; text-decoration: none; border-radius: 100px;">
    164                       Open Resend Dashboard
    165                     </a>
    166                   </td>
    167                 </tr>
    168               </table>
    169             </td>
    170           </tr>
    171 
    172         </table>
    173 
    174         <table border="0" cellspacing="0" cellpadding="0" style="max-width: 600px; width: 100%; margin-top: 32px;">
    175           <tr>
    176             <td align="center" style="padding-bottom: 24px;">
    177               <p class="text-secondary" style="margin: 0; font-family: Roboto, Arial, sans-serif; font-size: 12px; color: #747775; line-height: 1.6;">Automated alert by Notifier Bot.<br>Please do not reply to this unmonitored email.</p>
    178             </td>
    179           </tr>
    180           
    181           <tr>
    182             <td align="center" style="padding-bottom: 16px;">
    183               <table border="0" cellspacing="0" cellpadding="0">
    184                 <tr>
    185                   <td style="padding: 0 12px;">
    186                     <a href="https://amit.is-a.dev" target="_blank" style="text-decoration: none;" title="Website">
    187                       <svg width="20" height="20" viewBox="0 0 24 24" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
    188                         <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
    189                       </svg>
    190                     </a>
    191                   </td>
    192                   <td style="padding: 0 12px;">
    193                     <a href="https://github.com/notamitgamer" target="_blank" style="text-decoration: none;" title="GitHub">
    194                       <svg width="20" height="20" viewBox="0 0 16 16" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
    195                         <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
    196                       </svg>
    197                     </a>
    198                   </td>
    199                   <td style="padding: 0 12px;">
    200                     <a href="mailto:amitdutta4255@gmail.com" style="text-decoration: none;" title="Email">
    201                       <svg width="20" height="20" viewBox="0 0 24 24" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
    202                         <path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
    203                       </svg>
    204                     </a>
    205                   </td>
    206                 </tr>
    207               </table>
    208             </td>
    209           </tr>
    210 
    211           <tr>
    212             <td align="center">
    213               <p class="text-secondary" style="margin: 0; font-family: Roboto, Arial, sans-serif; font-size: 12px; color: #747775;">
    214                 &copy; 2025-2026 Amit Dutta &bull; <a href="https://amit.is-a.dev" class="text-secondary" style="color: #747775; text-decoration: none;">amit.is-a.dev</a>
    215               </p>
    216             </td>
    217           </tr>
    218         </table>
    219 
    220       </td>
    221     </tr>
    222   </table>
    223 
    224 </body>
    225 </html>
    226     `;
    227 
    228     const payload = {
    229       from: `Notifier Bot <${forwardingAddress}>`,
    230       to: [personalGmail],
    231       reply_to: originalSender, 
    232       subject: subject,
    233       html: notificationHtml
    234     };
    235 
    236     const { data, error } = await resend.emails.send(payload);
    237 
    238     if (error) {
    239       console.error(error);
    240       return res.status(500).json({ error: error.message });
    241     }
    242 
    243     return res.status(200).json({ success: true, id: data?.id });
    244 
    245   } catch (error) {
    246     console.error(error);
    247     return res.status(500).json({ error: 'Internal Server Error' });
    248   }
    249 });
    250 
    251 app.get('/ping', (req, res) => {
    252   res.status(200).send('Server is awake!');
    253 });
    254 
    255 app.listen(port, () => {
    256   console.log(`Email router listening on port ${port}`);
    257 });
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror