- Add complete dark mode system with theme context and toggle - Implement dark mode toggle component in navigation menu - Add client-side routing with SSR-safe signal handling - Fix language selector styling for better dark mode compatibility - Add documentation system with mdBook integration - Improve navigation menu with proper external/internal link handling - Add comprehensive project documentation and configuration - Enhance theme system with localStorage persistence - Fix arena panic issues during server-side rendering - Add proper TypeScript configuration and build optimizations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
17 KiB
Email System Documentation
This document provides comprehensive documentation for the Rustelo email system, including setup, configuration, usage, and examples.
Table of Contents
- Overview
- Features
- Quick Start
- Configuration
- Email Providers
- Templates
- API Endpoints
- Client Components
- Server Usage
- Environment Variables
- Security Considerations
- Troubleshooting
- Examples
Overview
The Rustelo email system provides a comprehensive solution for sending emails from your web application. It supports multiple email providers, template-based emails, form submissions, and both server-side and client-side integration.
Architecture
- Email Service: Core service that handles email sending
- Providers: Pluggable email providers (SMTP, SendGrid, Console)
- Templates: Handlebars-based email templates
- Forms: Ready-to-use contact and support form components
- API: REST endpoints for email operations
Features
✨ Multiple Providers
- SMTP (Gmail, Outlook, custom servers)
- SendGrid API
- Console output (development)
📧 Template System
- Handlebars templates
- HTML and text versions
- Custom helpers
- Variable substitution
🔧 Form Integration
- Contact forms
- Support forms with priorities
- Custom form handling
🛡️ Security
- Input validation
- Rate limiting
- CSRF protection
- Secure configuration
🎨 Rich Components
- React/Leptos form components
- Real-time validation
- Error handling
- Success feedback
Quick Start
1. Enable Email Feature
Make sure the email feature is enabled in your Cargo.toml:
[features]
default = ["email"]
email = ["lettre", "handlebars", "urlencoding"]
2. Basic Configuration
Add email configuration to your config.toml:
[email]
enabled = true
provider = "console" # Start with console for development
from_email = "noreply@yourapp.com"
from_name = "Your App"
template_dir = "templates/email"
3. Create Template Directory
mkdir -p templates/email/html
mkdir -p templates/email/text
4. Start Using
// Send a simple email
let result = email_service.send_simple_email(
"user@example.com",
"Welcome!",
"Thank you for signing up!"
).await?;
// Send a contact form
let result = email_service.send_contact_form(
"John Doe",
"john@example.com",
"Question about pricing",
"I'd like to know more about your pricing plans.",
"admin@yourapp.com"
).await?;
Configuration
Email Configuration Options
[email]
# Basic settings
enabled = true
provider = "smtp" # "smtp", "sendgrid", "console"
from_email = "noreply@yourapp.com"
from_name = "Your App Name"
template_dir = "templates/email"
# SMTP settings (when provider = "smtp")
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "your-email@gmail.com"
smtp_password = "your-app-password"
smtp_use_tls = false
smtp_use_starttls = true
# SendGrid settings (when provider = "sendgrid")
sendgrid_api_key = "your-sendgrid-api-key"
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
Environment-Specific Configuration
# Development
[environments.development]
email.provider = "console"
email.enabled = true
# Production
[environments.production]
email.provider = "sendgrid"
email.sendgrid_api_key = "${SENDGRID_API_KEY}"
email.enabled = true
Email Providers
Console Provider
Perfect for development and testing. Prints emails to the console.
[email]
provider = "console"
Features:
- No external dependencies
- Immediate feedback
- Safe for development
SMTP Provider
Use any SMTP server including Gmail, Outlook, or custom servers.
[email]
provider = "smtp"
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "your-email@gmail.com"
smtp_password = "your-app-password"
smtp_use_starttls = true
Common SMTP Configurations:
Gmail:
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_use_starttls = true
# Requires App Password (not regular password)
Outlook:
smtp_host = "smtp-mail.outlook.com"
smtp_port = 587
smtp_use_starttls = true
Custom Server:
smtp_host = "mail.yourdomain.com"
smtp_port = 587
smtp_use_starttls = true
SendGrid Provider
Professional email service with high deliverability.
[email]
provider = "sendgrid"
sendgrid_api_key = "your-api-key"
Setup Steps:
- Sign up at SendGrid
- Create an API key
- Verify your sender identity
- Add API key to configuration
Templates
Template Structure
Templates are organized in HTML and text directories:
templates/email/
├── html/
│ ├── contact.hbs
│ ├── notification.hbs
│ └── welcome.hbs
└── text/
├── contact.hbs
├── notification.hbs
└── welcome.hbs
Template Naming
Templates are named using the pattern: {template_name}_{format}.hbs
contact_html- HTML version of contact templatecontact_text- Text version of contact template
Handlebars Helpers
The system includes several built-in helpers:
Date Formatting:
{{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}
Capitalization:
{{capitalize form_type}}
Truncation:
{{truncate user_agent 100}}
Default Values:
{{default action_text "Take Action"}}
URL Encoding:
{{url_encode email}}
Example Template
HTML Template (contact.hbs):
<!DOCTYPE html>
<html>
<head>
<title>Contact Form Submission</title>
</head>
<body>
<h1>New Contact Form Submission</h1>
<p><strong>Name:</strong> {{name}}</p>
<p><strong>Email:</strong> {{email}}</p>
<p><strong>Subject:</strong> {{subject}}</p>
<div>
<strong>Message:</strong>
<p>{{message}}</p>
</div>
<hr>
<p>Submitted on {{date_format submitted_at}}</p>
</body>
</html>
Text Template (contact.hbs):
Contact Form Submission
Name: {{name}}
Email: {{email}}
Subject: {{subject}}
Message:
{{message}}
---
Submitted on {{date_format submitted_at}}
API Endpoints
GET /api/email/status
Get email service status and available templates.
Response:
{
"enabled": true,
"provider": "smtp",
"configured": true,
"templates": ["contact_html", "contact_text", "notification_html"]
}
POST /api/email/contact
Submit a contact form.
Request:
{
"name": "John Doe",
"email": "john@example.com",
"subject": "Question about pricing",
"message": "I'd like to know more about your plans.",
"recipient": "admin@yourapp.com"
}
Response:
{
"message": "Contact form submitted successfully",
"message_id": "smtp-1234567890",
"status": "sent"
}
POST /api/email/support
Submit a support form with priority and category.
Request:
{
"name": "Jane Smith",
"email": "jane@example.com",
"subject": "Login issues",
"message": "I can't log into my account.",
"priority": "high",
"category": "technical",
"recipient": "support@yourapp.com"
}
POST /api/email/send
Send a custom email (admin only).
Request:
{
"to": "user@example.com",
"subject": "Welcome to our service",
"template": "welcome",
"template_data": {
"user_name": "John",
"activation_link": "https://app.com/activate/123"
}
}
POST /api/email/notification
Send a notification email.
Request:
{
"to": "user@example.com",
"title": "Account Verification",
"message": "Please verify your email address",
"content": "<p>Click the link below to verify...</p>"
}
Client Components
ContactForm Component
import { ContactForm } from './components/forms';
<ContactForm
title="Get in Touch"
description="We'd love to hear from you"
recipient="contact@yourapp.com"
showSuccess={true}
resetAfterSuccess={true}
/>
Props:
recipient: Email address to send form totitle: Form titledescription: Form descriptionclass: Custom CSS classshowSuccess: Show success messageresetAfterSuccess: Reset form after successsubmitText: Custom submit button text
SupportForm Component
import { SupportForm } from './components/forms';
<SupportForm
title="Support Request"
recipient="support@yourapp.com"
showPriority={true}
showCategory={true}
categories={customCategories}
/>
Additional Props:
showPriority: Show priority selectorshowCategory: Show category selectorcategories: Custom category options
Form Validation
Both forms include comprehensive validation:
- Required field validation
- Email format validation
- Length limits
- Real-time error display
- Accessibility support
Server Usage
Basic Email Sending
use crate::email::{EmailService, EmailServiceBuilder};
// Initialize service
let email_service = EmailServiceBuilder::new()
.smtp_provider(smtp_config)
.default_from("noreply@app.com")
.default_from_name("My App")
.build()
.await?;
// Send simple email
let result = email_service.send_simple_email(
"user@example.com",
"Welcome!",
"Thank you for signing up!"
).await?;
Template-Based Emails
use std::collections::HashMap;
use serde_json::json;
let mut template_data = HashMap::new();
template_data.insert("user_name".to_string(), json!("John"));
template_data.insert("login_url".to_string(), json!("https://app.com/login"));
let result = email_service.send_templated_email(
"user@example.com",
"Welcome to Our Service",
"welcome",
template_data
).await?;
Form Handling
// Contact form
let result = email_service.send_contact_form(
"John Doe",
"john@example.com",
"Question",
"Message content",
"admin@app.com"
).await?;
// Support form
let result = email_service.send_support_form(
"Jane Smith",
"jane@example.com",
"Bug report",
"Description of the bug",
Some("high"), // priority
Some("technical"), // category
"support@app.com"
).await?;
Custom Email Messages
use crate::email::EmailMessage;
let message = EmailMessage::new("user@example.com", "Custom Subject")
.from("custom@app.com")
.from_name("Custom Sender")
.html_body("<h1>HTML Content</h1>")
.text_body("Text content")
.cc("manager@app.com")
.reply_to("reply@app.com");
let result = email_service.send_email(&message).await?;
Environment Variables
Common Variables
# SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-app-password
# SendGrid Configuration
SENDGRID_API_KEY=your-sendgrid-api-key
# General Email Settings
EMAIL_FROM_ADDRESS=noreply@yourapp.com
EMAIL_FROM_NAME="Your App Name"
EMAIL_ENABLED=true
Using in Configuration
[email]
smtp_username = "${SMTP_USERNAME}"
smtp_password = "${SMTP_PASSWORD}"
sendgrid_api_key = "${SENDGRID_API_KEY}"
from_email = "${EMAIL_FROM_ADDRESS}"
Security Considerations
1. Credential Management
❌ Never do:
# Don't commit real credentials
smtp_password = "real-password-123"
sendgrid_api_key = "SG.real-api-key"
✅ Do instead:
# Use environment variables
smtp_password = "${SMTP_PASSWORD}"
sendgrid_api_key = "${SENDGRID_API_KEY}"
2. Input Validation
All email inputs are validated:
- Email format validation
- Length limits (name: 100, subject: 200, message: 5000)
- Required field checking
- HTML sanitization
3. Rate Limiting
- Built-in rate limiting per IP address
- Configurable limits
- Automatic blocking of suspicious activity
4. CSRF Protection
- CSRF tokens on all forms
- Secure cookie settings
- SameSite cookie protection
5. Email Provider Security
Gmail:
- Use App Passwords, not regular passwords
- Enable 2-Factor Authentication
- Monitor for suspicious activity
SendGrid:
- Rotate API keys regularly
- Use least-privilege API keys
- Monitor sending quotas
Troubleshooting
Common Issues
1. Gmail Authentication Failed
Error: SMTP authentication failed
Solution:
- Enable 2-Factor Authentication
- Generate an App Password
- Use App Password instead of regular password
2. SendGrid 401 Unauthorized
Error: SendGrid API error: 401
Solution:
- Check API key is correct
- Verify API key has send permissions
- Ensure sender is verified
3. Template Not Found
Error: Template not found: welcome_html
Solution:
- Check template exists in correct directory
- Verify template naming convention
- Check template_dir configuration
4. Port Connection Refused
Error: Connection refused (port 587)
Solution:
- Check firewall settings
- Try different ports (465, 25)
- Verify SMTP server settings
Debug Mode
Enable debug logging to troubleshoot issues:
[logging]
level = "debug"
[email]
enabled = true
# Debug output will show detailed email information
Testing Email Delivery
1. Use Console Provider:
[email]
provider = "console"
2. Use Test SMTP Service:
- Mailtrap - Testing SMTP
- MailHog - Local testing
- Ethereal Email - Temporary testing
3. Check Email Status Endpoint:
curl http://localhost:3030/api/email/status
Examples
Complete Contact Page
use leptos::prelude::*;
use crate::components::ContactForm;
#[component]
pub fn ContactPage() -> impl IntoView {
view! {
<div class="max-w-2xl mx-auto py-12 px-4">
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-900 mb-4">
"Contact Us"
</h1>
<p class="text-lg text-gray-600">
"We'd love to hear from you. Send us a message and we'll respond as soon as possible."
</p>
</div>
<ContactForm
title="Send us a message"
recipient="contact@yourapp.com"
class="bg-white shadow-lg rounded-lg p-6"
/>
</div>
}
}
Custom Email Service Integration
use crate::email::{EmailService, EmailServiceBuilder, SmtpConfig};
pub async fn setup_email_service() -> Result<EmailService, Box<dyn std::error::Error>> {
let smtp_config = SmtpConfig {
host: "smtp.gmail.com".to_string(),
port: 587,
username: std::env::var("SMTP_USERNAME")?,
password: std::env::var("SMTP_PASSWORD")?,
use_tls: false,
use_starttls: true,
};
let service = EmailServiceBuilder::new()
.smtp_provider(smtp_config)
.default_from("noreply@yourapp.com")
.default_from_name("Your App")
.template_dir("./templates/email")
.enabled(true)
.build()
.await?;
Ok(service)
}
// Usage in your application
pub async fn send_welcome_email(
email_service: &EmailService,
user_email: &str,
user_name: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let mut template_data = HashMap::new();
template_data.insert("user_name".to_string(), json!(user_name));
template_data.insert("app_name".to_string(), json!("Your App"));
template_data.insert("support_email".to_string(), json!("support@yourapp.com"));
email_service.send_templated_email(
user_email,
"Welcome to Your App!",
"welcome",
template_data
).await?;
Ok(())
}
Advanced Form with Custom Fields
#[component]
pub fn CustomSupportForm() -> impl IntoView {
let custom_categories = vec![
CategoryOption {
value: "bug".to_string(),
label: "Bug Report".to_string(),
icon: "🐛".to_string(),
description: "Something isn't working correctly".to_string(),
},
CategoryOption {
value: "feature".to_string(),
label: "Feature Request".to_string(),
icon: "✨".to_string(),
description: "Suggest a new feature or improvement".to_string(),
},
CategoryOption {
value: "billing".to_string(),
label: "Billing Question".to_string(),
icon: "💳".to_string(),
description: "Questions about your account or billing".to_string(),
},
];
view! {
<SupportForm
title="Support Request"
description="Tell us how we can help you"
recipient="support@yourapp.com"
categories=custom_categories
show_priority=true
show_category=true
submit_text="Submit Support Request"
class="max-w-lg mx-auto"
/>
}
}
This email system provides a robust, secure, and user-friendly solution for all your application's email needs. From simple notifications to complex form handling, it scales with your application's requirements while maintaining security and reliability.