From 3d987d0c68926c248baad62e9afaf9e7f3476e1b Mon Sep 17 00:00:00 2001 From: Alaguraj0361 Date: Mon, 18 May 2026 22:50:47 +0530 Subject: [PATCH] feat: Add order summary table and customer info to custom email, remove shipping address --- mailer.js | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- server.js | 2 +- 2 files changed, 206 insertions(+), 8 deletions(-) diff --git a/mailer.js b/mailer.js index 6bd22ae..8952b26 100644 --- a/mailer.js +++ b/mailer.js @@ -1,18 +1,16 @@ const nodemailer = require('nodemailer'); /** - * Sends an email with the PDF attachment. + * Sends a premium custom email with the PDF attachment. * @param {string} toEmail - The recipient's email address - * @param {string|number} orderNumber - The Shopify order number + * @param {Object} orderData - The Shopify order payload * @param {Buffer} pdfBuffer - The PDF data buffer */ -const sendEmailWithAttachment = async (toEmail, orderNumber, pdfBuffer) => { - // Create a transporter using your email service credentials - // You can configure SMTP, SendGrid, Amazon SES, etc. +const sendEmailWithAttachment = async (toEmail, orderData, pdfBuffer) => { const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: Number(process.env.SMTP_PORT) || 465, - secure: process.env.SMTP_SECURE === 'true', // true for 465, false for other ports + secure: process.env.SMTP_SECURE === 'true', auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS, @@ -22,12 +20,212 @@ const sendEmailWithAttachment = async (toEmail, orderNumber, pdfBuffer) => { } }); + const orderNumber = orderData.order_number || orderData.name; + const currencySymbol = orderData.currency === 'INR' ? 'Rs. ' : `${orderData.currency} `; + + // --- 1. Generate Order Summary Rows HTML --- + let orderRowsHtml = ''; + if (orderData.line_items && orderData.line_items.length > 0) { + orderData.line_items.forEach(item => { + const itemImageUrl = item.image || (item.featured_image && item.featured_image.url) || ''; + const imageHtml = itemImageUrl + ? ` + ${item.title} + ` + : ` +
+ `; + + const variantText = item.variant_title ? `${item.variant_title}` : ''; + const itemTotal = (parseFloat(item.price) * item.quantity).toFixed(2); + + orderRowsHtml += ` + + ${imageHtml} + + ${item.title || item.name} × ${item.quantity} + ${variantText} + + + ${currencySymbol}${itemTotal} + + + `; + }); + } + + // --- 2. Calculate Totals --- + const subtotal = parseFloat(orderData.subtotal_price).toFixed(2); + const shipping = parseFloat(orderData.total_shipping_price_set?.shop_money?.amount || 0).toFixed(2); + const taxes = parseFloat(orderData.total_tax || 0).toFixed(2); + const total = parseFloat(orderData.total_price).toFixed(2); + + let taxRow = ''; + if (parseFloat(taxes) > 0) { + taxRow = ` + + Taxes + ${currencySymbol}${taxes} + + `; + } + + // --- 3. Billing Address Details HTML --- + const billing = orderData.billing_address || {}; + let billingAddressHtml = ''; + if (billing.first_name || billing.last_name) { + billingAddressHtml += `${billing.first_name || ''} ${billing.last_name || ''}
`; + } + if (billing.address1) billingAddressHtml += `${billing.address1}
`; + if (billing.address2) billingAddressHtml += `${billing.address2}
`; + if (billing.city || billing.province || billing.zip) { + billingAddressHtml += `${billing.city || ''} ${billing.province || ''} ${billing.zip || ''}
`; + } + if (billing.country) billingAddressHtml += `${billing.country}
`; + if (billing.phone || orderData.phone) { + billingAddressHtml += `${billing.phone || orderData.phone}`; + } + + const paymentMethod = orderData.gateway || 'Request Quote'; + const shippingMethod = orderData.shipping_lines?.[0]?.title || 'Economy'; + + // --- 4. Beautiful Responsive HTML Template --- + const htmlTemplate = ` + + + + + + Order Confirmation + + + + + + +
+ + + + + + + + + + + + + + ${orderData.order_status_url ? ` + + + + ` : ''} + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ rayaarishop + + Order #${orderNumber} +
+
+

Thank you for your order!

+

+ We're getting your order ready to be shipped. We have attached your custom PDF invoice directly to this email. +

+
+ + View your order + + or Visit our store +
+

Order summary

+
+ + ${orderRowsHtml} +
+
+ + + + + + + + + + ${taxRow} + + + + +
Subtotal${currencySymbol}${subtotal}
Shipping${currencySymbol}${shipping}
Total + ${currencySymbol}${total} ${orderData.currency} +
+
+

Customer information

+
+ + + + + + + + +
+ Billing address + ${billingAddressHtml} + + Payment method + ${paymentMethod} + + Shipping method + ${shippingMethod} +
+
+
+ + + `; + const mailOptions = { from: `"${process.env.SHOP_NAME || 'Your Store'}" <${process.env.SMTP_FROM_EMAIL}>`, to: toEmail, subject: `Invoice for your order #${orderNumber}`, text: `Thank you for your order! Attached is the invoice for order #${orderNumber}.`, - html: `

Thank you for your order!

Attached is the invoice for order #${orderNumber}.

`, + html: htmlTemplate, attachments: [ { filename: `Invoice_${orderNumber}.pdf`, diff --git a/server.js b/server.js index f132fa0..434d1c9 100644 --- a/server.js +++ b/server.js @@ -63,7 +63,7 @@ app.post('/webhooks/orders/create', verifyShopifyWebhook, async (req, res) => { await sendEmailWithAttachment( customerEmail, - orderData.order_number, + orderData, pdfBuffer );