
Email Service Integration
- 424 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
email-service-integration is a Backend & APIs skill that wires transactional and marketing email into applications using SendGrid, SES, or Postmark with templates, webhooks, and deliverability checks for developers who n
About
email-service-integration is a useful-ai-prompts skill that walks developers through connecting application backends to email providers such as SendGrid, Amazon SES, and Postmark. The skill covers API key setup, HTML and text template design, webhook handlers for bounces and complaints, and basic deliverability checks so password resets, receipts, and lifecycle campaigns actually reach inboxes. Developers reach for email-service-integration when a SaaS or API product needs outbound email beyond local SMTP stubs. The skill emphasizes provider-specific integration patterns, webhook verification, and template variables rather than generic email copywriting.
- Provider selection and API setup
- Transactional vs marketing email flows
- Template and variable management
- Webhook handling for bounces and events
- Deliverability and compliance basics
Email Service Integration by the numbers
- 424 all-time installs (skills.sh)
- Ranked #1,000 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill email-service-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 424 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you integrate transactional email into a SaaS app?
Wire transactional and marketing email into apps using providers like SendGrid, SES, or Postmark with templates, webhooks, and deliverability checks.
Who is it for?
Backend developers adding production transactional or marketing email to a SaaS or API product with bounce and complaint webhook handling.
Skip if: Teams that only need local Mailhog testing, already have a fully configured email platform, or want broadcast-only tools without application code integration.
When should I use this skill?
A developer needs to add password reset, receipt, or lifecycle email sending with SendGrid, SES, or Postmark and webhook event handling.
What you get
Provider SDK integration, email templates, webhook handlers, and deliverability check configuration
- Email provider SDK integration
- Template files
- Webhook handler endpoints
Files
Email Service Integration
Table of Contents
Overview
Build comprehensive email systems with SMTP integration, third-party email providers (SendGrid, Mailgun, AWS SES), HTML templates, email validation, retry mechanisms, and proper error handling.
When to Use
- Sending transactional emails
- Implementing welcome/confirmation emails
- Creating password reset flows
- Sending notification emails
- Building email templates
- Managing bulk email campaigns
Quick Start
Minimal working example:
# config.py
import os
class EmailConfig:
MAIL_SERVER = os.getenv('MAIL_SERVER', 'smtp.gmail.com')
MAIL_PORT = int(os.getenv('MAIL_PORT', 587))
MAIL_USE_TLS = os.getenv('MAIL_USE_TLS', True)
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER', 'noreply@example.com')
# email_service.py
from flask_mail import Mail, Message
from flask import render_template_string
import logging
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
logger = logging.getLogger(__name__)
mail = Mail()
class EmailService:
def __init__(self, app=None):
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Python/Flask with SMTP | Python/Flask with SMTP |
| Node.js with SendGrid | Node.js with SendGrid |
| Email Templates with Mjml | Email Templates with Mjml |
| FastAPI Email with Background Tasks | FastAPI Email with Background Tasks |
| Email Validation and Verification | Email Validation and Verification |
Best Practices
✅ DO
- Use transactional email providers for reliability
- Implement email templates for consistency
- Add unsubscribe links (required by law)
- Use background tasks for email sending
- Implement proper error handling and retries
- Validate email addresses before sending
- Add rate limiting to prevent abuse
- Monitor email delivery and bounces
- Use SMTP authentication
- Test emails in development environment
❌ DON'T
- Send emails synchronously in request handlers
- Store passwords in code
- Send sensitive information in emails
- Use generic email addresses for sensitive operations
- Skip email validation
- Ignore bounce and complaint notifications
- Use HTML email with inline styles excessively
- Forget to handle failed email deliveries
- Send emails without proper templates
- Store email addresses without consent
Email Templates with Mjml
Email Templates with Mjml
<!-- templates/welcome.mjml -->
<mjml>
<mj-body>
<mj-container>
<mj-section>
<mj-column>
<mj-image width="100px" src="https://example.com/logo.png"></mj-image>
</mj-column>
</mj-section>
<mj-section background-color="#f4f4f4">
<mj-column>
<mj-text font-size="24px" align="center" color="#333">
Welcome, {{ userName }}!
</mj-text>
<mj-text align="center" color="#666">
Thank you for joining us. Let's get started!
</mj-text>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-button
href="https://example.com/dashboard"
background-color="#007bff"
>
Go to Dashboard
</mj-button>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-text font-size="12px" align="center" color="#999">
© 2024 Example Inc. All rights reserved.
</mj-text>
</mj-column>
</mj-section>
</mj-container>
</mj-body>
</mjml>
<!-- Python template compilation -->
# email_templates.py from mjml import mjml_to_html def
get_welcome_template(user_name): with open('templates/welcome.mjml', 'r') as f:
mjml_content = f.read() mjml_content = mjml_content.replace('{{ userName }}',
user_name) html = mjml_to_html(mjml_content) return htmlEmail Validation and Verification
Email Validation and Verification
# email_validator.py
import re
from email_validator import validate_email, EmailNotValidError
import dns.resolver
class EmailValidator:
@staticmethod
def validate_format(email: str) -> tuple:
"""Validate email format"""
try:
valid = validate_email(email)
return True, valid.email
except EmailNotValidError as e:
return False, str(e)
@staticmethod
def check_mx_records(email: str) -> bool:
"""Check MX records for domain"""
try:
domain = email.split('@')[1]
mx_records = dns.resolver.resolve(domain, 'MX')
return len(mx_records) > 0
except Exception:
return False
@staticmethod
def validate_email_comprehensive(email: str) -> dict:
"""Comprehensive email validation"""
# Format validation
is_valid, message = EmailValidator.validate_format(email)
if not is_valid:
return {'valid': False, 'reason': 'Invalid format'}
# MX record check
has_mx = EmailValidator.check_mx_records(email)
if not has_mx:
return {'valid': False, 'reason': 'Domain has no MX records'}
return {'valid': True, 'email': email}FastAPI Email with Background Tasks
FastAPI Email with Background Tasks
# email_service.py
from fastapi import BackgroundTasks
from fastapi_mail import FastMail, MessageSchema, ConnectionConfig
conf = ConnectionConfig(
mail_server=os.getenv("MAIL_SERVER"),
mail_port=int(os.getenv("MAIL_PORT")),
mail_from=os.getenv("MAIL_FROM"),
mail_password=os.getenv("MAIL_PASSWORD"),
mail_from_name=os.getenv("MAIL_FROM_NAME", "Example App"),
use_credentials=True,
validate_certs=True
)
fm = FastMail(conf)
class EmailService:
@staticmethod
async def send_email(
recipients: list,
subject: str,
body: str,
background_tasks: BackgroundTasks = None
):
message = MessageSchema(
subject=subject,
recipients=recipients,
body=body,
subtype="html"
)
if background_tasks:
background_tasks.add_task(fm.send_message, message)
else:
await fm.send_message(message)
@staticmethod
async def send_welcome_email(
email: str,
name: str,
background_tasks: BackgroundTasks
):
html_body = f"""
<h1>Welcome, {name}!</h1>
<p>Thank you for joining us.</p>
<a href="https://example.com/dashboard">Start Exploring</a>
"""
await EmailService.send_email(
recipients=[email],
subject="Welcome to Our Platform!",
body=html_body,
background_tasks=background_tasks
)
# routes.py
from fastapi import BackgroundTasks
from email_service import EmailService
@app.post("/api/send-email")
async def send_email(
email: str,
background_tasks: BackgroundTasks
):
await EmailService.send_welcome_email(email, "User", background_tasks)
return {"message": "Email queued for sending"}Node.js with SendGrid
Node.js with SendGrid
// email-service.js
const sgMail = require("@sendgrid/mail");
const logger = require("./logger");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
class EmailService {
async sendEmail(to, subject, htmlContent, textContent = null) {
try {
const msg = {
to: Array.isArray(to) ? to : [to],
from: process.env.MAIL_FROM || "noreply@example.com",
subject: subject,
html: htmlContent,
...(textContent && { text: textContent }),
};
const result = await sgMail.send(msg);
logger.info(`Email sent to ${to}: ${subject}`);
return { success: true, messageId: result[0].headers["x-message-id"] };
} catch (error) {
logger.error(`Failed to send email: ${error.message}`);
return { success: false, error: error.message };
}
}
async sendWelcomeEmail(to, userName) {
const htmlContent = `
<h1>Welcome, ${userName}!</h1>
<p>Thank you for joining us.</p>
<a href="https://example.com/dashboard">Start Exploring</a>
`;
return this.sendEmail(to, "Welcome to Our Platform!", htmlContent);
}
async sendPasswordResetEmail(to, resetToken) {
const resetUrl = `https://example.com/reset-password?token=${resetToken}`;
const htmlContent = `
<h1>Reset Your Password</h1>
<p>Click the link below to reset your password:</p>
<a href="${resetUrl}">Reset Password</a>
<p>This link expires in 24 hours.</p>
`;
return this.sendEmail(to, "Reset Your Password", htmlContent);
}
async sendVerificationEmail(to, verificationToken) {
const verifyUrl = `https://example.com/verify-email?token=${verificationToken}`;
const htmlContent = `
<h1>Verify Your Email</h1>
<p>Click the link below to verify your email:</p>
<a href="${verifyUrl}">Verify Email</a>
`;
return this.sendEmail(to, "Verify Your Email", htmlContent);
}
async sendBulkEmails(recipients, subject, htmlContent) {
try {
const personalizations = recipients.map((recipient) => ({
to: [{ email: recipient.email }],
substitutions: {
"-name-": recipient.name,
},
}));
const msg = {
personalizations: personalizations,
from: process.env.MAIL_FROM || "noreply@example.com",
subject: subject,
html: htmlContent,
};
const result = await sgMail.send(msg);
logger.info(`Bulk email sent to ${recipients.length} recipients`);
return { success: true, sent: recipients.length };
} catch (error) {
logger.error(`Bulk email failed: ${error.message}`);
return { success: false, error: error.message };
}
}
}
module.exports = new EmailService();
// routes.js
const express = require("express");
const emailService = require("../services/email-service");
const { generateToken } = require("../utils/token");
const router = express.Router();
router.post("/send-verification", async (req, res) => {
try {
const { email } = req.body;
if (!email) {
return res.status(400).json({ error: "Email required" });
}
const verificationToken = generateToken();
const result = await emailService.sendVerificationEmail(
email,
verificationToken,
);
if (result.success) {
// Store token in database
await VerificationToken.create({ email, token: verificationToken });
return res.json({ message: "Verification email sent" });
} else {
return res.status(500).json({ error: "Failed to send email" });
}
} catch (error) {
logger.error(error);
res.status(500).json({ error: "Internal server error" });
}
});
router.post("/send-reset", async (req, res) => {
try {
const { email } = req.body;
const user = await User.findOne({ where: { email } });
if (!user) {
return res.json({ message: "If email exists, reset link sent" });
}
const resetToken = generateToken();
const result = await emailService.sendPasswordResetEmail(email, resetToken);
if (result.success) {
await ResetToken.create({ userId: user.id, token: resetToken });
return res.json({ message: "Reset email sent" });
} else {
return res.status(500).json({ error: "Failed to send email" });
}
} catch (error) {
res.status(500).json({ error: "Internal server error" });
}
});
module.exports = router;Python/Flask with SMTP
Python/Flask with SMTP
# config.py
import os
class EmailConfig:
MAIL_SERVER = os.getenv('MAIL_SERVER', 'smtp.gmail.com')
MAIL_PORT = int(os.getenv('MAIL_PORT', 587))
MAIL_USE_TLS = os.getenv('MAIL_USE_TLS', True)
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER', 'noreply@example.com')
# email_service.py
from flask_mail import Mail, Message
from flask import render_template_string
import logging
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
logger = logging.getLogger(__name__)
mail = Mail()
class EmailService:
def __init__(self, app=None):
self.app = app
if app:
mail.init_app(app)
def send_email(self, recipient, subject, text_body=None, html_body=None):
"""Send email using Flask-Mail"""
try:
msg = Message(
subject=subject,
recipients=[recipient] if isinstance(recipient, str) else recipient
)
if text_body:
msg.body = text_body
if html_body:
msg.html = html_body
mail.send(msg)
logger.info(f"Email sent to {recipient}: {subject}")
return True
except Exception as e:
logger.error(f"Failed to send email to {recipient}: {str(e)}")
return False
def send_welcome_email(self, user_email, user_name):
"""Send welcome email"""
subject = "Welcome to Our Platform!"
html_body = render_template_string(
'''
<h1>Welcome, {{ name }}!</h1>
<p>Thank you for joining us. Start exploring now!</p>
<a href="https://example.com/dashboard">Go to Dashboard</a>
''',
name=user_name
)
return self.send_email(user_email, subject, html_body=html_body)
def send_password_reset_email(self, user_email, reset_token):
"""Send password reset email"""
subject = "Reset Your Password"
reset_url = f"https://example.com/reset-password?token={reset_token}"
html_body = render_template_string(
'''
<h1>Reset Your Password</h1>
<p>Click the link below to reset your password:</p>
<a href="{{ reset_url }}">Reset Password</a>
<p>This link expires in 24 hours.</p>
''',
reset_url=reset_url
)
return self.send_email(user_email, subject, html_body=html_body)
def send_verification_email(self, user_email, verification_token):
"""Send email verification"""
subject = "Verify Your Email"
verify_url = f"https://example.com/verify-email?token={verification_token}"
html_body = render_template_string(
'''
<h1>Verify Your Email Address</h1>
<p>Click the link below to verify your email:</p>
<a href="{{ verify_url }}">Verify Email</a>
''',
verify_url=verify_url
)
return self.send_email(user_email, subject, html_body=html_body)
def send_notification_email(self, user_email, notification_data):
"""Send notification email"""
subject = notification_data.get('subject', 'Notification')
html_body = render_template_string(
'''
<h1>{{ title }}</h1>
<p>{{ message }}</p>
{{ content|safe }}
''',
title=notification_data.get('title'),
message=notification_data.get('message'),
content=notification_data.get('html_content', '')
)
return self.send_email(user_email, subject, html_body=html_body)
# routes.py
from flask import Blueprint, request, jsonify
from email_service import EmailService
email_bp = Blueprint('email', __name__)
email_service = EmailService()
@email_bp.route('/api/auth/send-verification', methods=['POST'])
def send_verification():
"""Send verification email"""
data = request.json
user_email = data.get('email')
verification_token = generate_token()
success = email_service.send_verification_email(user_email, verification_token)
if success:
# Store token in database
VerificationToken.create(email=user_email, token=verification_token)
return jsonify({'message': 'Verification email sent'}), 200
else:
return jsonify({'error': 'Failed to send email'}), 500
@email_bp.route('/api/auth/send-reset', methods=['POST'])
def send_reset():
"""Send password reset email"""
data = request.json
user = User.query.filter_by(email=data['email']).first()
if not user:
# Don't reveal if email exists
return jsonify({'message': 'If email exists, reset link sent'}), 200
reset_token = generate_token()
success = email_service.send_password_reset_email(user.email, reset_token)
if success:
ResetToken.create(user_id=user.id, token=reset_token)
return jsonify({'message': 'Reset email sent'}), 200
else:
return jsonify({'error': 'Failed to send email'}), 500#!/bin/bash
# validate-pipeline.sh - Validate CI/CD pipeline configuration
# Usage: ./validate-pipeline.sh <pipeline_file>
set -euo pipefail
PIPELINE_FILE="${{1:?Usage: $0 <pipeline_file>}}"
echo "Validating pipeline: $PIPELINE_FILE"
# TODO: Add pipeline validation
# - Check YAML/Groovy syntax
# - Verify stage dependencies
# - Check for required stages (build, test, deploy)
# - Validate environment variable references
# - Check for security best practices
echo "Pipeline validation complete."
# CI/CD Pipeline Starter Template
# TODO: Customize for your CI/CD platform (GitHub Actions, GitLab CI, Jenkins, etc.)
name: CI/CD Pipeline
# TODO: Configure triggers
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# TODO: Add build steps
test:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
# TODO: Add test steps
deploy:
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
# TODO: Add deployment steps
- run: echo "Deploy to production"
Related skills
FAQ
Which email providers does email-service-integration cover?
email-service-integration covers SendGrid, Amazon SES, and Postmark integration with templates, webhooks, and deliverability checks. The skill targets transactional and marketing email wired into application backends.
What webhooks should email integration handle?
email-service-integration configures webhooks for bounces, complaints, and delivery events so backends can suppress bad addresses and log failures. Provider-specific signature verification is part of the setup.