Rustelo/docs/email.md

821 lines
17 KiB
Markdown
Raw Normal View History

# Email System Documentation
This document provides comprehensive documentation for the Rustelo email system, including setup, configuration, usage, and examples.
## Table of Contents
- [Overview](#overview)
- [Features](#features)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Email Providers](#email-providers)
- [Templates](#templates)
- [API Endpoints](#api-endpoints)
- [Client Components](#client-components)
- [Server Usage](#server-usage)
- [Environment Variables](#environment-variables)
- [Security Considerations](#security-considerations)
- [Troubleshooting](#troubleshooting)
- [Examples](#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`:
```toml
[features]
default = ["email"]
email = ["lettre", "handlebars", "urlencoding"]
```
### 2. Basic Configuration
Add email configuration to your `config.toml`:
```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
```bash
mkdir -p templates/email/html
mkdir -p templates/email/text
```
### 4. Start Using
```rust
// 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
```toml
[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
```toml
# 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.
```toml
[email]
provider = "console"
```
**Features:**
- No external dependencies
- Immediate feedback
- Safe for development
### SMTP Provider
Use any SMTP server including Gmail, Outlook, or custom servers.
```toml
[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:**
```toml
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_use_starttls = true
# Requires App Password (not regular password)
```
**Outlook:**
```toml
smtp_host = "smtp-mail.outlook.com"
smtp_port = 587
smtp_use_starttls = true
```
**Custom Server:**
```toml
smtp_host = "mail.yourdomain.com"
smtp_port = 587
smtp_use_starttls = true
```
### SendGrid Provider
Professional email service with high deliverability.
```toml
[email]
provider = "sendgrid"
sendgrid_api_key = "your-api-key"
```
**Setup Steps:**
1. Sign up at [SendGrid](https://sendgrid.com)
2. Create an API key
3. Verify your sender identity
4. 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 template
- `contact_text` - Text version of contact template
### Handlebars Helpers
The system includes several built-in helpers:
**Date Formatting:**
```handlebars
{{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}
```
**Capitalization:**
```handlebars
{{capitalize form_type}}
```
**Truncation:**
```handlebars
{{truncate user_agent 100}}
```
**Default Values:**
```handlebars
{{default action_text "Take Action"}}
```
**URL Encoding:**
```handlebars
{{url_encode email}}
```
### Example Template
**HTML Template (contact.hbs):**
```html
<!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):**
```text
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:**
```json
{
"enabled": true,
"provider": "smtp",
"configured": true,
"templates": ["contact_html", "contact_text", "notification_html"]
}
```
### POST /api/email/contact
Submit a contact form.
**Request:**
```json
{
"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:**
```json
{
"message": "Contact form submitted successfully",
"message_id": "smtp-1234567890",
"status": "sent"
}
```
### POST /api/email/support
Submit a support form with priority and category.
**Request:**
```json
{
"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:**
```json
{
"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:**
```json
{
"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
```jsx
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 to
- `title`: Form title
- `description`: Form description
- `class`: Custom CSS class
- `showSuccess`: Show success message
- `resetAfterSuccess`: Reset form after success
- `submitText`: Custom submit button text
### SupportForm Component
```jsx
import { SupportForm } from './components/forms';
<SupportForm
title="Support Request"
recipient="support@yourapp.com"
showPriority={true}
showCategory={true}
categories={customCategories}
/>
```
**Additional Props:**
- `showPriority`: Show priority selector
- `showCategory`: Show category selector
- `categories`: 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
```rust
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
```rust
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
```rust
// 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
```rust
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
```bash
# 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
```toml
[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:**
```toml
# Don't commit real credentials
smtp_password = "real-password-123"
sendgrid_api_key = "SG.real-api-key"
```
**✅ Do instead:**
```toml
# 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:
```toml
[logging]
level = "debug"
[email]
enabled = true
# Debug output will show detailed email information
```
### Testing Email Delivery
**1. Use Console Provider:**
```toml
[email]
provider = "console"
```
**2. Use Test SMTP Service:**
- [Mailtrap](https://mailtrap.io) - Testing SMTP
- [MailHog](https://github.com/mailhog/MailHog) - Local testing
- [Ethereal Email](https://ethereal.email) - Temporary testing
**3. Check Email Status Endpoint:**
```bash
curl http://localhost:3030/api/email/status
```
## Examples
### Complete Contact Page
```rust
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
```rust
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
```rust
#[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"
/>
}
}
```
2026-02-08 20:37:49 +00:00
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.