Jesús Pérez 0d0297423e
Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
chore: fix with CI and pre-commit
2026-02-08 20:37:49 +00:00

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

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:

  1. Sign up at SendGrid
  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:

{{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 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

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

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:

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.