
Email Service Integration
- 58 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Send reliable transactional emails via SendGrid, SES, or Postmark with SPF/DKIM/DMARC records, templates, and bounce handling.
About
Covers wiring a dedicated transactional email service per platform with deliverability DNS records and reusable templates. A developer uses it to set up order-confirmation email or fix messages landing in spam.
- Per-platform default-email vs recommended-upgrade table
- SPF/DKIM/DMARC setup plus bounce and complaint handling
Email Service Integration by the numbers
- 58 all-time installs (skills.sh)
- Ranked #3,178 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill email-service-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 58 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Send reliable transactional emails via SendGrid, SES, or Postmark with SPF/DKIM/DMARC records, templates, and bounce handling.
Files
Email Service Integration
Overview
Transactional emails — order confirmations, shipping notifications, password resets, and account alerts — are critical customer touchpoints that must arrive instantly and reliably. This skill covers setting up email delivery on each platform and integrating dedicated transactional services (SendGrid, Amazon SES, Postmark) with SPF/DKIM/DMARC DNS records for deliverability, reusable templates, and bounce/complaint handling.
When to Use This Skill
- When setting up transactional email for a new e-commerce store
- When emails are landing in spam due to missing SPF, DKIM, or DMARC records
- When migrating from a platform's built-in email to a dedicated transactional service
- When building custom email templates that match your brand identity
- When tracking email delivery, open rates, and bounces for transactional emails
Core Instructions
Step 1: Determine your platform and recommended approach
| Platform | Default Email | Recommended Upgrade |
|---|---|---|
| Shopify | Shopify Email (built-in, branded templates, free up to 10K/month) | Customize templates in Settings → Notifications; for high volume or advanced flows use Klaviyo or Omnisend |
| WooCommerce | WordPress sends via your hosting server (poor deliverability) | Install FluentSMTP (free) to route via SendGrid/SES/Postmark; use WooCommerce Email Customizer ($49) for branded templates |
| BigCommerce | BigCommerce built-in transactional email (basic templates) | Customize templates in Marketing → Transactional Emails; for advanced templates use Klaviyo BigCommerce integration |
| Custom / Headless | None — you build it | Integrate SendGrid, Postmark, or Amazon SES directly; build templates with React Email; see implementation below |
Step 2: Platform-specific email setup
---
Shopify
Customize built-in transactional emails:
1. Go to Settings → Notifications in your Shopify admin 2. Click any notification type (Order Confirmation, Shipping Notification, etc.) to open the editor 3. Edit the HTML/Liquid template directly — Shopify provides liquid variables for order data 4. Upload your logo in Online Store → Themes → Customize → Theme settings → Logo — it appears automatically in notification emails 5. In Settings → General, set your sender email — Shopify authenticates it automatically via SPF/DKIM
Set up Shopify Email for marketing flows:
1. Go to Apps → Shopify Email (free, included with all plans up to 10,000 emails/month) 2. Build order confirmation, shipping, and post-purchase flows with the drag-and-drop editor 3. For advanced automations (abandoned cart sequences, win-back flows) upgrade to Klaviyo (free up to 500 contacts) which has a pre-built Shopify integration
---
WooCommerce
Fix email deliverability with FluentSMTP:
1. Install FluentSMTP (free, wordpress.org) — this replaces WordPress's built-in PHP mail with a dedicated SMTP or API provider 2. Go to FluentSMTP → Settings → Add New Connection 3. Choose your provider: SendGrid (free tier: 100 emails/day), Mailgun (free tier: 1,000 emails/month), or Amazon SES ($0.10/1,000 emails) 4. Enter your API key and set From Name and From Email to match your domain 5. Send a test email from FluentSMTP to verify delivery
Set up SPF and DKIM for your sending domain:
Most providers give you specific DNS records to add. For SendGrid:
- Add the two CNAME records SendGrid provides to your DNS (usually in your domain registrar or Cloudflare)
- In SendGrid, verify the domain — this takes up to 48 hours to propagate
- After verification, emails show "via yourdomain.com" in Gmail, not "via sendgrid.net"
Customize WooCommerce email templates:
1. Install Email Customizer for WooCommerce by ThemeHigh (free tier; Pro from $49) 2. Go to WooCommerce → Email Customizer to drag-and-drop your logo, colors, and footer into each email type 3. Or install Kadence WooCommerce Email Designer (free) for a live preview editor
---
BigCommerce
Customize transactional email templates:
1. Go to Marketing → Transactional Emails in your BigCommerce admin 2. Click any email type (Order Confirmation, Shipment Notification, etc.) and click Edit Template 3. Edit the HTML template using BigCommerce's template variables (e.g., %%ORDER_NUMBER%%, %%TOTAL_COST%%) 4. In Store Setup → Store Profile, set your sending name and reply-to address
Connect Klaviyo for advanced flows:
1. Install the Klaviyo app from the BigCommerce App Marketplace (free to install) 2. Klaviyo syncs your BigCommerce order and customer data automatically 3. Use Klaviyo's pre-built BigCommerce flows for order confirmation, shipping, and abandoned cart emails
---
Custom / Headless
Configure DNS for deliverability first — SPF, DKIM, and DMARC are mandatory before any emails reach inboxes:
; SPF — authorize SendGrid to send on behalf of your domain
mystore.com. IN TXT "v=spf1 include:sendgrid.net ~all"
; DKIM — SendGrid provides two CNAME records:
s1._domainkey.mystore.com IN CNAME s1.domainkey.u12345.wl.sendgrid.net.
s2._domainkey.mystore.com IN CNAME s2.domainkey.u12345.wl.sendgrid.net.
; DMARC — start with p=none to monitor, then escalate to p=quarantine
_dmarc.mystore.com IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@mystore.com"Verify with mxtoolbox.com/SuperTool.aspx before sending.
SendGrid API integration:
// lib/email/sendgrid.ts
import sgMail from '@sendgrid/mail';
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
export async function sendEmail(params: {
to: string;
subject: string;
html: string;
text: string;
}) {
await sgMail.send({
to: params.to,
from: { email: 'orders@mystore.com', name: 'My Store' },
subject: params.subject,
html: params.html,
text: params.text,
trackingSettings: {
clickTracking: { enable: false }, // Don't wrap links in transactional emails
openTracking: { enable: true },
},
});
}Build templates with React Email (npm install @react-email/components):
// emails/order-confirmation.tsx
import { Body, Container, Heading, Html, Img, Preview, Section, Text, Row, Column } from '@react-email/components';
export function OrderConfirmationEmail({ orderNumber, customerName, items, total, trackingUrl }) {
return (
<Html>
<Preview>Your order #{orderNumber} is confirmed</Preview>
<Body style={{ backgroundColor: '#f4f4f4', fontFamily: 'Arial, sans-serif' }}>
<Container style={{ maxWidth: '600px', margin: '0 auto', backgroundColor: '#fff', padding: '20px' }}>
<Heading>Order Confirmed</Heading>
<Text>Hi {customerName}, your order #{orderNumber} has been received.</Text>
{items.map((item, i) => (
<Row key={i} style={{ borderBottom: '1px solid #eee', padding: '10px 0' }}>
<Column style={{ width: '60px' }}>
<Img src={item.imageUrl} width={50} height={50} alt={item.name} />
</Column>
<Column>
<Text style={{ margin: 0, fontWeight: 'bold' }}>{item.name}</Text>
<Text style={{ margin: 0, color: '#666' }}>Qty: {item.quantity}</Text>
</Column>
<Column style={{ textAlign: 'right' }}>
<Text style={{ margin: 0 }}>{item.price}</Text>
</Column>
</Row>
))}
<Section style={{ marginTop: '20px' }}>
<Text style={{ fontWeight: 'bold', fontSize: '18px' }}>Total: {total}</Text>
</Section>
</Container>
</Body>
</Html>
);
}Render and send:
import { render } from '@react-email/render';
import { OrderConfirmationEmail } from '../../emails/order-confirmation';
import { sendEmail } from './sendgrid';
export async function sendOrderConfirmation(order: Order) {
const html = await render(OrderConfirmationEmail({ ...orderData }));
const text = await render(OrderConfirmationEmail({ ...orderData }), { plainText: true });
await sendEmail({
to: order.customer.email,
subject: `Your order #${order.number} is confirmed`,
html,
text,
});
}Handle bounces and complaints via webhook:
// POST /api/webhooks/sendgrid
export async function POST(req: NextRequest) {
const events = await req.json();
for (const event of events) {
if (event.event === 'bounce') {
await db.emailSuppressions.upsert({ email: event.email, type: 'hard_bounce' });
}
if (event.event === 'spamreport') {
await db.emailSuppressions.upsert({ email: event.email, type: 'spam_complaint' });
}
}
return NextResponse.json({ received: true });
}
// Check suppression list before every send
export async function canSendEmail(email: string): Promise<boolean> {
const suppression = await db.emailSuppressions.findByEmail(email.toLowerCase());
return !suppression; // Never send to hard bounced or spam-complaint addresses
}Best Practices
- Use separate sending domains for transactional and marketing emails — bounces and spam complaints from marketing campaigns should not affect your transactional domain reputation
- Always include a plain-text version — missing plain text can trigger spam filters; React Email renders it automatically with
{ plainText: true } - Suppress hard bounced addresses immediately — sending to non-existent addresses harms your sender reputation; store and check suppressions before every send
- Never track clicks in transactional emails — link tracking wraps URLs in redirects, which can look suspicious in password reset and order confirmation emails
- Test rendering across email clients — Outlook, Gmail, and Apple Mail render HTML very differently; use Litmus or Email on Acid to validate before deploying templates
Common Pitfalls
| Problem | Solution |
|---|---|
| WooCommerce emails going to spam | Install FluentSMTP to send via SendGrid or SES; WordPress's default PHP mail has no SPF/DKIM and almost always gets marked as spam |
| SES sandbox blocking delivery | New AWS accounts start in SES sandbox mode — request production access via AWS Support before going live |
| Duplicate order confirmation emails | Implement idempotent sending: emailId = hash(orderId + 'order-confirmation') and check before sending |
| Emails landing in spam despite SPF/DKIM | Check DMARC alignment; your From: domain must match the domain in the DKIM d= tag |
| React Email CSS broken in Outlook | Use inline styles for everything; Outlook ignores <style> blocks; @react-email/components handles this for built-in components |
Related Skills
- @gdpr-ecommerce
- @webhook-architecture
- @analytics-integration
{
"context": "Tests whether the agent correctly implements SendGrid webhook event handling with proper suppression storage, and builds a pre-send suppression check that applies the correct blocking rules for transactional vs marketing emails.",
"type": "weighted_checklist",
"checklist": [
{
"name": "bounce event handled",
"max_score": 8,
"description": "Webhook handler has a case/branch for 'bounce' events that stores the email address as suppressed"
},
{
"name": "spamreport event handled",
"max_score": 8,
"description": "Webhook handler has a case/branch for 'spamreport' events that stores the email address as suppressed"
},
{
"name": "unsubscribe event handled",
"max_score": 7,
"description": "Webhook handler has a case/branch for 'unsubscribe' events that updates email/marketing consent"
},
{
"name": "delivered event handled",
"max_score": 7,
"description": "Webhook handler has a case/branch for 'delivered' events that updates the delivery record status"
},
{
"name": "hard_bounce suppression type",
"max_score": 8,
"description": "Bounce events are stored with a suppression type of 'hard_bounce' (not 'bounce' or other variant)"
},
{
"name": "spam_complaint suppression type",
"max_score": 8,
"description": "Spam report events are stored with a suppression type of 'spam_complaint' (not 'spam' or other variant)"
},
{
"name": "Email lowercased on storage",
"max_score": 6,
"description": "Email addresses are normalized to lowercase (e.g. email.toLowerCase()) before being stored in the suppression record"
},
{
"name": "Hard bounce blocks all email",
"max_score": 10,
"description": "The pre-send suppression check returns false (blocks sending) for hard_bounce regardless of whether the email type is transactional or marketing"
},
{
"name": "Spam/unsubscribe blocks only marketing",
"max_score": 10,
"description": "The pre-send suppression check allows transactional email through for spam_complaint or unsubscribe suppressions, but blocks marketing email"
},
{
"name": "No suppression allows all",
"max_score": 7,
"description": "The pre-send check returns true (allows sending) when no suppression record exists for the email address"
},
{
"name": "CAN-SPAM/GDPR unsubscribe in marketing",
"max_score": 8,
"description": "Code or documentation notes that marketing emails must include an unsubscribe link (referencing CAN-SPAM and/or GDPR)"
},
{
"name": "No click tracking in transactional",
"max_score": 7,
"description": "Any send function for transactional emails in the implementation disables click tracking (e.g. TrackLinks: 'None' or clickTracking.enable: false)"
},
{
"name": "Webhook returns received response",
"max_score": 6,
"description": "Webhook POST handler returns a success response (e.g. {received: true} or HTTP 200) after processing events"
}
]
}
Email Deliverability and Suppression System
Problem/Feature Description
A growing e-commerce platform recently onboarded SendGrid for transactional and promotional email. Within weeks, their sender reputation dropped — some addresses that had previously bounced were still receiving emails, and a surge of spam complaints followed a promotional campaign. The deliverability team has been asked to build two things: a webhook endpoint that captures delivery events and maintains a suppression list, and a utility function that checks whether it is safe to email a given address before any send is attempted.
The suppression rules are not symmetric: a user whose mailbox no longer exists should never receive any email, but a user who marked a promotional email as spam should still receive their order receipts and shipping notifications. Your implementation needs to handle this distinction correctly so that neither deliverability nor customer experience is compromised.
Output Specification
Produce the following files:
app/api/webhooks/sendgrid/route.ts— A Next.js (App Router) POST route handler that processes a JSON array of SendGrid delivery events. It should handle the relevant event types and maintain a suppression list and delivery log. The handler should return an appropriate response on success.lib/email/suppression.ts— A module that exports acanSendEmail(email: string, type: 'transactional' | 'marketing'): Promise<boolean>function. The function checks the suppression list and applies the correct blocking rules depending on the suppression type and the requested email type.README.md— A short document (bullet points are fine) explaining the suppression rules enforced bycanSendEmailand which legal requirements apply to marketing emails.
You do not need a running database — use stub/mock DB calls or inline comments to indicate where real persistence would go. Focus on the logic and structure of the implementation.
{
"context": "Tests whether the agent uses the correct Postmark package and API patterns, applies the right MessageStream and tracking settings for transactional vs marketing sending, uses the template API correctly, and separates sending domains for transactional and marketing emails. Also covers DNS record configuration for deliverability.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Postmark npm package",
"max_score": 8,
"description": "Uses the 'postmark' npm package (importing ServerClient from 'postmark'), not an unofficial or generic HTTP client"
},
{
"name": "API token from env",
"max_score": 7,
"description": "Instantiates ServerClient with the token sourced from an environment variable (e.g. process.env.POSTMARK_API_TOKEN)"
},
{
"name": "Transactional MessageStream",
"max_score": 9,
"description": "Sets MessageStream to 'outbound' for transactional email sends"
},
{
"name": "Marketing MessageStream",
"max_score": 9,
"description": "Sets MessageStream to 'broadcasts' for marketing/promotional email sends"
},
{
"name": "TrackLinks None",
"max_score": 8,
"description": "Sets TrackLinks to 'None' for transactional email sends (link tracking disabled)"
},
{
"name": "TrackOpens true",
"max_score": 8,
"description": "Sets TrackOpens to true for email sends"
},
{
"name": "Template API used",
"max_score": 9,
"description": "Uses postmark.sendEmailWithTemplate() with TemplateAlias and TemplateModel for at least one template-based send"
},
{
"name": "Separate sending domains",
"max_score": 9,
"description": "Uses distinct From addresses or domains for transactional and marketing emails (e.g. noreply@mystore.com vs newsletters@mail.mystore.com or equivalent domain separation)"
},
{
"name": "SPF record documented",
"max_score": 10,
"description": "Includes or documents an SPF TXT record in the DNS setup section using v=spf1 syntax"
},
{
"name": "DKIM records documented",
"max_score": 9,
"description": "Includes or documents DKIM CNAME records provided by the email provider in the DNS setup section"
},
{
"name": "DMARC record documented",
"max_score": 9,
"description": "Includes or documents a DMARC TXT record (_dmarc.) in the DNS setup section"
},
{
"name": "DMARC escalation policy",
"max_score": 5,
"description": "Documents the DMARC policy escalation approach: starting with p=none before moving to p=quarantine and then p=reject"
}
]
}
Postmark Email Integration for New E-Commerce Platform
Problem/Feature Description
A new direct-to-consumer brand is launching their online store and needs to set up their entire email infrastructure from scratch. They plan to send both transactional emails (order confirmations, shipping updates, password resets) and occasional promotional campaigns to opted-in customers. After researching providers, the team has chosen Postmark because of its reputation for transactional deliverability and dedicated IP pools.
The tech lead has asked you to build the email sending layer in TypeScript and produce a DNS setup guide for the domain administrator. The guide needs to cover everything required to achieve inbox delivery. The code should support both direct message sending and Postmark's managed template system (which the design team will use to maintain brand consistency). A key architectural concern: the marketing team's campaign activity should never be able to damage the reputation of the transactional sending pipeline, so the sending configuration must enforce this isolation.
Output Specification
Produce the following files:
lib/email/postmark.ts— A TypeScript module exporting at least:- A function for sending a transactional email directly (with HTML and text body)
- A function for sending a marketing/promotional email directly
- A function for sending via Postmark's managed template system
dns-setup.md— A DNS configuration guide for the domain administrator covering the records needed for email deliverability, including any recommended progression for policy configuration.package.json— Listing the required dependencies.
You do not need a running Postmark account — use environment variable placeholders for credentials. Focus on the structure and correctness of the implementation.
{
"context": "Tests whether the agent uses the correct SendGrid package and configuration, builds React Email templates with the correct component library, generates both HTML and plain-text output, and applies the correct tracking settings for transactional emails.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Correct SendGrid package",
"max_score": 8,
"description": "Uses @sendgrid/mail (not @sendgrid/client or other variants) as the npm dependency for sending emails"
},
{
"name": "API key configuration",
"max_score": 8,
"description": "Calls sgMail.setApiKey() with the API key sourced from an environment variable (e.g. process.env.SENDGRID_API_KEY)"
},
{
"name": "Click tracking disabled",
"max_score": 10,
"description": "Sets clickTracking.enable to false (and/or enableText to false) in trackingSettings when sending transactional email via SendGrid"
},
{
"name": "Open tracking enabled",
"max_score": 8,
"description": "Sets openTracking.enable to true in trackingSettings when sending via SendGrid"
},
{
"name": "React Email component library",
"max_score": 10,
"description": "Imports template components from @react-email/components (e.g. Body, Container, Heading, Html, Text, Preview, or similar)"
},
{
"name": "React Email render package",
"max_score": 8,
"description": "Uses the render() function from @react-email/render to convert React components to HTML"
},
{
"name": "HTML version generated",
"max_score": 8,
"description": "Calls render() without the plainText option to produce the HTML body of the email"
},
{
"name": "Plain-text version generated",
"max_score": 10,
"description": "Calls render() with {plainText: true} (or equivalent) to produce a text/plain body and passes it to the send function"
},
{
"name": "Inline styles used",
"max_score": 8,
"description": "Email template uses inline style objects on components rather than external CSS classes or a <style> block for layout and visual styling"
},
{
"name": "Idempotent send guard",
"max_score": 10,
"description": "Implements a check before sending (e.g. hashing order ID + template name and comparing to a stored record) to prevent duplicate emails from being sent for the same event"
},
{
"name": "Preview component included",
"max_score": 6,
"description": "Email template includes a <Preview> component from @react-email/components to set the preview text shown in email client inboxes"
},
{
"name": "TypeScript interface for email data",
"max_score": 6,
"description": "Defines a typed interface (or type) for the email's template data/props rather than using untyped objects"
}
]
}
Order Confirmation Email Module
Problem/Feature Description
A mid-sized online retailer is rebuilding their post-purchase communication flow. Currently they send plain HTML emails directly from their backend, which are frequently flagged as spam and look broken in Outlook and mobile clients. The engineering team has decided to adopt a dedicated transactional email provider and a React-based template system so that the marketing and engineering teams can iterate on email designs independently from the send logic.
Your task is to build the order confirmation email module. This includes a reusable React email template component and the TypeScript send function that renders and delivers it via SendGrid. The module should be production-ready: it must work correctly the first time an order triggers it and never accidentally send the same confirmation twice, even under retry conditions.
Output Specification
Produce the following files in your working directory:
emails/order-confirmation.tsx— A React Email template component for order confirmations. It should accept order data as props and render a complete, styled email showing the order number, customer name, ordered items (with product name, quantity, and price), and order total.lib/email/sendgrid.ts— A TypeScript module that exports asendEmailfunction using SendGrid.lib/email/send-order-confirmation.ts— A TypeScript module that renders the template and callssendEmail, including a guard against sending duplicate confirmation emails for the same order.package.json— Listing all required dependencies.
You do not need to set up a real database or API key — use stubs or comments where actual DB/API calls would go. Focus on the structure and implementation approach, not running the code end-to-end.
{
"name": "finsi/email-service-integration",
"version": "0.1.0",
"summary": "Transactional email setup (SendGrid, SES, Postmark) with template management",
"skills": {
"email-service-integration": {
"path": "SKILL.md"
}
}
}