---
name: Wheels Email Generator
description: Generate email functionality including mailer controllers, email templates, and configuration. Use when sending emails, creating notifications, or implementing transactional emails. Ensures proper email structure, layouts, and testing.
---
# Wheels Email Generator
## When to Use This Skill
Activate automatically when:
- User wants to send emails
- User mentions: email, mailer, sendMail, notification
- User needs password reset emails
- User wants welcome emails or transactional emails
- User asks about email templates or configuration
## Email Directory Structure
```
/app/
├── controllers/
│ └── Mailer.cfc # Email controller
├── views/
│ └── mailer/ # Email templates
│ ├── layouts/
│ │ ├── email.cfm # HTML layout
│ │ └── email.txt.cfm # Plain text layout
│ ├── welcome.cfm # HTML version
│ ├── welcome.txt.cfm # Text version
│ ├── resetPassword.cfm
│ └── resetPassword.txt.cfm
└── /config/
└── settings.cfm # Email configuration
```
## Mailer Controller Template
```cfm
component extends="Controller" {
function config() {
// Configure email defaults
set(
functionName = "sendEmail",
from = "noreply@yourapp.com",
layout = "email",
detectMultipart = true
);
}
/**
* Send welcome email to new user
*/
function welcome(required user) {
sendEmail(
to = arguments.user.email,
subject = "Welcome to Our App!",
template = "mailer/welcome",
user = arguments.user
);
}
/**
* Send password reset email
*/
function resetPassword(required user, required token) {
local.resetUrl = URLFor(
route = "passwordReset",
token = arguments.token,
onlyPath = false
);
sendEmail(
to = arguments.user.email,
subject = "Reset Your Password",
template = "mailer/resetPassword",
user = arguments.user,
resetUrl = local.resetUrl
);
}
/**
* Send order confirmation email
*/
function orderConfirmation(required order) {
sendEmail(
to = arguments.order.customerEmail,
subject = "Order Confirmation - ##" & arguments.order.id,
template = "mailer/orderConfirmation",
order = arguments.order
);
}
/**
* Send notification to admin
*/
function adminNotification(required subject, required message) {
sendEmail(
to = application.adminEmail,
subject = arguments.subject,
template = "mailer/adminNotification",
message = arguments.message
);
}
}
```
## Email Layout (HTML) - views/mailer/layouts/email.cfm
```cfm
##contentForLayout()##
```
## Email Layout (Plain Text) - views/mailer/layouts/email.txt.cfm
```cfm
========================================
YOUR APP NAME
========================================
##contentForLayout()##
========================================
© #Year(Now())# Your Company
All rights reserved.
Unsubscribe: [URL]
Privacy: [URL]
========================================
```
## Email Template Examples
### Welcome Email (HTML) - views/mailer/welcome.cfm
```cfm
Welcome, ##user.firstName##!
Thank you for joining our community. We're excited to have you on board.
Here's what you can do next:
- Complete your profile
- Explore our features
- Connect with other users
Get Started
If you have any questions, feel free to reply to this email.
Best regards,
The Team
```
### Welcome Email (Plain Text) - views/mailer/welcome.txt.cfm
```cfm
Welcome, ##user.firstName##!
Thank you for joining our community. We're excited to have you on board.
Here's what you can do next:
- Complete your profile
- Explore our features
- Connect with other users
Get Started: ##URLFor(route='dashboard', onlyPath=false)##
If you have any questions, feel free to reply to this email.
Best regards,
The Team
```
### Password Reset Email - views/mailer/resetPassword.cfm
```cfm
Reset Your Password
Hi ##user.firstName##,
We received a request to reset your password. Click the button below to create a new password:
Reset Password
Or copy and paste this link into your browser:
##resetUrl##
This link will expire in 24 hours.
If you didn't request a password reset, you can safely ignore this email.
Thanks,
The Security Team
```
## Email Configuration - config/settings.cfm
```cfm
// Email Server Configuration
set(
functionName = "sendEmail",
server = "smtp.gmail.com",
port = 587,
username = "your-email@gmail.com",
password = "your-app-password",
useTLS = true,
useSSL = false,
from = "noreply@yourapp.com",
type = "html",
charset = "utf-8"
);
// Environment-Specific Email Settings
if (application.wheels.environment == "development") {
// Log emails instead of sending
set(functionName = "sendEmail", debug = true, deliver = false);
}
if (application.wheels.environment == "testing") {
// Send all emails to test account
set(functionName = "sendEmail", to = "test@yourapp.com");
}
if (application.wheels.environment == "production") {
// Production settings
set(
functionName = "sendEmail",
server = getEnv("SMTP_SERVER"),
username = getEnv("SMTP_USERNAME"),
password = getEnv("SMTP_PASSWORD"),
deliver = true
);
}
```
## Using the Mailer
### In Controllers
```cfm
component extends="Controller" {
function create() {
user = model("User").new(params.user);
if (user.save()) {
// Send welcome email
controller("Mailer").welcome(user);
redirectTo(route="home", success="Account created! Check your email.");
} else {
renderView(action="new");
}
}
function forgotPassword() {
user = model("User").findOne(where="email='#params.email#'");
if (isObject(user)) {
// Generate reset token
token = createUUID();
user.update(resetToken=token, resetTokenExpiry=dateAdd("h", 24, now()));
// Send reset email
controller("Mailer").resetPassword(user=user, token=token);
flashInsert(success="Password reset instructions sent to your email.");
}
redirectTo(action="login");
}
}
```
### Direct Usage
```cfm
// Simple email
sendEmail(
to = "user@example.com",
from = "noreply@yourapp.com",
subject = "Test Email",
body = "This is a test email."
);
// Email with template
sendEmail(
to = "user@example.com",
subject = "Custom Email",
template = "mailer/custom",
customVariable = "value"
);
// Email with attachments
sendEmail(
to = "user@example.com",
subject = "Invoice",
template = "mailer/invoice",
file = expandPath("./uploads/invoice.pdf"),
fileName = "invoice-##123##.pdf"
);
```
## Email with File Attachments
```cfm
function sendInvoice(required order) {
local.pdfPath = expandPath("./temp/invoice-##arguments.order.id##.pdf");
// Generate PDF invoice
generateInvoicePDF(arguments.order, local.pdfPath);
// Send email with attachment
sendEmail(
to = arguments.order.customerEmail,
subject = "Your Invoice - Order ##arguments.order.id##",
template = "mailer/invoice",
order = arguments.order,
file = local.pdfPath,
fileName = "invoice-##arguments.order.id##.pdf"
);
// Clean up temp file
fileDelete(local.pdfPath);
}
```
## Email with Multiple Recipients
```cfm
function sendNewsletter(required subject, required template) {
// Get all subscribed users
subscribers = model("User").findAll(where="subscribed=1");
// Send to each subscriber
for (local.subscriber in subscribers) {
sendEmail(
to = local.subscriber.email,
subject = arguments.subject,
template = arguments.template,
user = local.subscriber
);
}
}
```
## Testing Emails
### Email Test
```cfm
component extends="wheels.Test" {
function testWelcomeEmailSent() {
// Create test user
user = model("User").create(
email = "test@example.com",
firstName = "Test"
);
// Call mailer
controller("Mailer").welcome(user);
// Verify email was queued
assert("application.wheels.emailQueue.len() > 0");
}
function testPasswordResetEmail() {
user = model("User").findByKey(1);
token = createUUID();
controller("Mailer").resetPassword(user=user, token=token);
// Check email contains reset link
lastEmail = application.wheels.emailQueue[1];
assert("findNoCase('reset', lastEmail.body) > 0");
assert("findNoCase(token, lastEmail.body) > 0");
}
}
```
### Manual Testing
```cfm
// Test in browser - add route
.get(name="testEmail", pattern="/test/email", to="tests##testEmail")
// Test controller
function testEmail() {
user = model("User").findByKey(1);
controller("Mailer").welcome(user);
renderText("Email sent! Check server logs.");
}
```
## Email Best Practices
### ✅ DO:
- Always provide both HTML and plain text versions
- Use responsive email layouts (max-width: 600px)
- Include unsubscribe links
- Test emails across different clients
- Use descriptive subject lines
- Handle email failures gracefully
- Queue emails for bulk sending
- Use environment-specific settings
### ❌ DON'T:
- Send emails synchronously in production
- Hardcode email addresses
- Use complex CSS (limited support)
- Forget error handling
- Send without user consent
- Include sensitive data in emails
- Use JavaScript in emails
## Common Email Patterns
### 1. Transactional Emails
```cfm
// Order confirmation, password resets, account verification
- Time-sensitive
- User-triggered
- High priority
```
### 2. Notification Emails
```cfm
// Activity updates, mentions, reminders
- Event-driven
- May be batched
- User preferences apply
```
### 3. Marketing Emails
```cfm
// Newsletters, promotions
- Bulk sending
- Unsubscribe required
- Scheduled
```
## Email Queue Pattern
```cfm
// Queue email for background processing
function queueEmail(required struct emailData) {
model("EmailQueue").create(
recipient = arguments.emailData.to,
subject = arguments.emailData.subject,
template = arguments.emailData.template,
data = serializeJSON(arguments.emailData),
status = "pending"
);
}
// Process queue (run via scheduled task)
function processEmailQueue() {
pending = model("EmailQueue").findAll(
where = "status='pending'",
order = "createdAt",
maxRows = 50
);
for (local.email in pending) {
try {
local.data = deserializeJSON(local.email.data);
sendEmail(argumentCollection=local.data);
local.email.update(status="sent", sentAt=now());
} catch (any e) {
local.email.update(
status = "failed",
errorMessage = e.message
);
}
}
}
```
## SMTP Providers
### Gmail
```cfm
server = "smtp.gmail.com"
port = 587
useTLS = true
// Note: Use app password, not account password
```
### SendGrid
```cfm
server = "smtp.sendgrid.net"
port = 587
username = "apikey"
password = "YOUR_API_KEY"
useTLS = true
```
### Mailgun
```cfm
server = "smtp.mailgun.org"
port = 587
username = "postmaster@yourdomain.mailgun.org"
password = "YOUR_PASSWORD"
useTLS = true
```
### AWS SES
```cfm
server = "email-smtp.us-east-1.amazonaws.com"
port = 587
username = "YOUR_SMTP_USERNAME"
password = "YOUR_SMTP_PASSWORD"
useTLS = true
```
## Related Skills
- **wheels-controller-generator**: Create mailer controllers
- **wheels-view-generator**: Create email templates
- **wheels-auth-generator**: Password reset emails
- **wheels-test-generator**: Test email functionality
---
**Generated by:** Wheels Email Generator Skill v1.0