# Email System

<div align="center">
  <img src="../../../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
</div>

This guide covers RUSTELO's comprehensive email system, including setup, configuration, usage, and best practices for integrating email functionality into your application.

## Overview

The RUSTELO email system provides a complete solution for sending emails from your web application with support for multiple 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 = "@encrypted_smtp_password"
smtp_use_tls = false
smtp_use_starttls = true

# SendGrid settings (when provider = "sendgrid")
sendgrid_api_key = "@encrypted_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 = "@encrypted_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 = "@encrypted_smtp_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 SMTP:**
```toml
smtp_host = "mail.yourserver.com"
smtp_port = 587
smtp_use_starttls = true
```

### SendGrid Provider

Use SendGrid's API for reliable email delivery.

```toml
[email]
provider = "sendgrid"
sendgrid_api_key = "@encrypted_sendgrid_api_key"
```

**Features:**
- High deliverability
- Built-in analytics
- Bounce handling
- Reliable service

## Templates

### Template Structure

```
templates/email/
├── html/
│   ├── contact.hbs
│   ├── support.hbs
│   ├── welcome.hbs
│   └── notification.hbs
└── text/
    ├── contact.hbs
    ├── support.hbs
    ├── welcome.hbs
    └── notification.hbs
```

### Template Naming

- `contact.hbs` - Contact form emails
- `support.hbs` - Support form emails
- `welcome.hbs` - Welcome/registration emails
- `notification.hbs` - General notifications

### Handlebars Helpers

Built-in helpers for common email tasks:

- `{{format_date}}` - Format dates
- `{{format_currency}}` - Format money
- `{{upper}}` - Uppercase text
- `{{lower}}` - Lowercase text
- `{{capitalize}}` - Capitalize words

### Example Template

**templates/email/html/contact.hbs:**

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Contact Form Submission</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .header { background-color: #f8f9fa; padding: 20px; border-radius: 8px; }
        .content { margin: 20px 0; }
        .footer { color: #666; font-size: 12px; }
    </style>
</head>
<body>
    <div class="header">
        <h1>New Contact Form Submission</h1>
    </div>
    
    <div class="content">
        <p><strong>Name:</strong> {{name}}</p>
        <p><strong>Email:</strong> {{email}}</p>
        <p><strong>Subject:</strong> {{subject}}</p>
        <p><strong>Message:</strong></p>
        <p>{{message}}</p>
    </div>
    
    <div class="footer">
        <p>Sent at {{format_date timestamp}}</p>
    </div>
</body>
</html>
```

**templates/email/text/contact.hbs:**

```text
New Contact Form Submission

Name: {{name}}
Email: {{email}}
Subject: {{subject}}

Message:
{{message}}

Sent at {{format_date timestamp}}
```

## API Endpoints

### GET /api/email/status

Check email system status.

**Response:**
```json
{
  "enabled": true,
  "provider": "smtp",
  "configured": true,
  "templates": ["contact", "support", "welcome", "notification"]
}
```

### POST /api/email/contact

Send a contact form email.

**Request:**
```json
{
  "name": "John Doe",
  "email": "john@example.com",
  "subject": "Question about pricing",
  "message": "I'd like to know more about your pricing plans.",
  "recipient": "admin@yourapp.com"
}
```

**Response:**
```json
{
  "message": "Email sent successfully",
  "message_id": "abc123def456",
  "status": "sent"
}
```

### POST /api/email/support

Send a support form email with priority.

**Request:**
```json
{
  "name": "Jane Smith",
  "email": "jane@example.com",
  "subject": "Technical Issue",
  "message": "Having trouble with login functionality.",
  "priority": "high",
  "category": "technical",
  "recipient": "support@yourapp.com"
}
```

### POST /api/email/send

Send a template-based email.

**Request:**
```json
{
  "to": "user@example.com",
  "subject": "Welcome to Our Platform",
  "template": "welcome",
  "template_data": {
    "user_name": "John Doe",
    "activation_link": "https://yourapp.com/activate/token123"
  }
}
```

### POST /api/email/notification

Send a notification email.

**Request:**
```json
{
  "to": "user@example.com",
  "title": "Important Update",
  "message": "Your account has been updated successfully.",
  "content": "Additional details about the update..."
}
```

## Client Components

### ContactForm Component

```rust
#[component]
pub fn ContactForm() -> impl IntoView {
    let (form_data, set_form_data) = create_signal(ContactFormData::default());
    let (is_submitting, set_is_submitting) = create_signal(false);
    let (message, set_message) = create_signal(String::new());

    let submit_form = create_action(move |data: &ContactFormData| {
        let data = data.clone();
        async move {
            set_is_submitting(true);
            let result = send_contact_form(data).await;
            set_is_submitting(false);
            match result {
                Ok(_) => set_message("Thank you for your message! We'll get back to you soon.".to_string()),
                Err(e) => set_message(format!("Error sending message: {}", e)),
            }
        }
    });

    view! {
        <div class="contact-form">
            <h2>"Contact Us"</h2>
            <form on:submit=move |ev| {
                ev.prevent_default();
                submit_form.dispatch(form_data.get());
            }>
                <div class="form-group">
                    <label for="name">"Name"</label>
                    <input
                        type="text"
                        id="name"
                        required
                        on:input=move |ev| {
                            set_form_data.update(|data| data.name = event_target_value(&ev));
                        }
                    />
                </div>
                
                <div class="form-group">
                    <label for="email">"Email"</label>
                    <input
                        type="email"
                        id="email"
                        required
                        on:input=move |ev| {
                            set_form_data.update(|data| data.email = event_target_value(&ev));
                        }
                    />
                </div>
                
                <div class="form-group">
                    <label for="subject">"Subject"</label>
                    <input
                        type="text"
                        id="subject"
                        required
                        on:input=move |ev| {
                            set_form_data.update(|data| data.subject = event_target_value(&ev));
                        }
                    />
                </div>
                
                <div class="form-group">
                    <label for="message">"Message"</label>
                    <textarea
                        id="message"
                        required
                        on:input=move |ev| {
                            set_form_data.update(|data| data.message = event_target_value(&ev));
                        }
                    ></textarea>
                </div>
                
                <button type="submit" disabled=move || is_submitting.get()>
                    {move || if is_submitting.get() { "Sending..." } else { "Send Message" }}
                </button>
            </form>
            
            <Show when=move || !message.get().is_empty()>
                <div class="message">{move || message.get()}</div>
            </Show>
        </div>
    }
}
```

### SupportForm Component

```rust
#[component]
pub fn SupportForm() -> impl IntoView {
    let (form_data, set_form_data) = create_signal(SupportFormData::default());
    let (is_submitting, set_is_submitting) = create_signal(false);
    let (message, set_message) = create_signal(String::new());

    let submit_form = create_action(move |data: &SupportFormData| {
        let data = data.clone();
        async move {
            set_is_submitting(true);
            let result = send_support_form(data).await;
            set_is_submitting(false);
            match result {
                Ok(_) => set_message("Support ticket submitted successfully!".to_string()),
                Err(e) => set_message(format!("Error submitting ticket: {}", e)),
            }
        }
    });

    view! {
        <div class="support-form">
            <h2>"Support Request"</h2>
            <form on:submit=move |ev| {
                ev.prevent_default();
                submit_form.dispatch(form_data.get());
            }>
                // Similar form fields with priority selector
                <div class="form-group">
                    <label for="priority">"Priority"</label>
                    <select
                        id="priority"
                        on:change=move |ev| {
                            set_form_data.update(|data| data.priority = event_target_value(&ev));
                        }
                    >
                        <option value="low">"Low"</option>
                        <option value="medium">"Medium"</option>
                        <option value="high">"High"</option>
                        <option value="urgent">"Urgent"</option>
                    </select>
                </div>
                
                <button type="submit" disabled=move || is_submitting.get()>
                    {move || if is_submitting.get() { "Submitting..." } else { "Submit Ticket" }}
                </button>
            </form>
        </div>
    }
}
```

## Server Usage

### Basic Email Sending

```rust
use server::email::{EmailService, EmailConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = EmailConfig::from_file("config.toml")?;
    let email_service = EmailService::new(config).await?;
    
    // Send simple email
    email_service.send_simple_email(
        "user@example.com",
        "Welcome!",
        "Thank you for signing up!"
    ).await?;
    
    Ok(())
}
```

### Template-Based Emails

```rust
use std::collections::HashMap;

#[server(SendWelcomeEmail, "/api/email/welcome")]
pub async fn send_welcome_email(
    email: String,
    name: String,
    activation_token: String,
) -> Result<String, ServerFnError> {
    let email_service = get_email_service().await?;
    
    let mut template_data = HashMap::new();
    template_data.insert("user_name".to_string(), name);
    template_data.insert("activation_link".to_string(), 
        format!("https://yourapp.com/activate/{}", activation_token));
    
    email_service.send_template_email(
        &email,
        "Welcome to Our Platform",
        "welcome",
        template_data
    ).await?;
    
    Ok("Welcome email sent successfully".to_string())
}
```

### Form Handling

```rust
#[server(HandleContactForm, "/api/email/contact")]
pub async fn handle_contact_form(
    name: String,
    email: String,
    subject: String,
    message: String,
) -> Result<String, ServerFnError> {
    let email_service = get_email_service().await?;
    
    // Validate input
    if name.is_empty() || email.is_empty() || message.is_empty() {
        return Err(ServerFnError::ServerError("All fields are required".to_string()));
    }
    
    // Send email
    email_service.send_contact_form(
        &name,
        &email,
        &subject,
        &message,
        "admin@yourapp.com"
    ).await?;
    
    Ok("Contact form submitted successfully".to_string())
}
```

## 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
SMTP_USE_STARTTLS=true

# SendGrid Configuration
SENDGRID_API_KEY=your-sendgrid-api-key

# Email Settings
EMAIL_FROM=noreply@yourapp.com
EMAIL_FROM_NAME="Your App"
```

### Using in Configuration

```toml
[email]
smtp_username = "${SMTP_USERNAME}"
smtp_password = "@encrypted_smtp_password"
sendgrid_api_key = "@encrypted_sendgrid_api_key"
from_email = "${EMAIL_FROM}"
```

## Security Considerations

### 1. Credential Management

Always encrypt sensitive credentials:

```bash
# Encrypt SMTP password
cargo run --bin config_crypto_tool encrypt "your-smtp-password"

# Encrypt SendGrid API key
cargo run --bin config_crypto_tool encrypt "your-sendgrid-api-key"
```

### 2. Input Validation

Always validate email inputs:

```rust
use validator::{Validate, ValidationError};

#[derive(Validate)]
struct ContactFormData {
    #[validate(length(min = 1, message = "Name is required"))]
    name: String,
    
    #[validate(email(message = "Invalid email address"))]
    email: String,
    
    #[validate(length(min = 1, max = 1000, message = "Message must be between 1 and 1000 characters"))]
    message: String,
}
```

### 3. Rate Limiting

Implement rate limiting for email endpoints:

```rust
use tower_governor::{governor::GovernorLayer, GovernorConfigBuilder};

// Limit to 5 emails per minute per IP
let governor_config = GovernorConfigBuilder::default()
    .per_minute(5)
    .burst_size(2)
    .finish()
    .unwrap();

let governor_layer = GovernorLayer {
    config: Arc::new(governor_config),
};
```

### 4. CSRF Protection

Enable CSRF protection for email forms:

```rust
use axum_csrf::{CsrfConfig, CsrfLayer};

let csrf_config = CsrfConfig::default();
let csrf_layer = CsrfLayer::new(csrf_config);
```

## Troubleshooting

### Common Issues

**Email not sending:**
- Check provider configuration
- Verify credentials
- Check network connectivity
- Review email service logs

**Template not found:**
- Verify template directory path
- Check template file naming
- Ensure HTML and text versions exist

**Authentication failed:**
- For Gmail: Use App Password, not regular password
- For other providers: Check username/password
- Verify server and port settings

**Rate limiting:**
- Check provider limits
- Implement proper rate limiting
- Consider using queues for bulk emails

### Debug Mode

Enable debug logging to troubleshoot issues:

```toml
[logging]
level = "debug"

[email]
enabled = true
debug = true
```

## Best Practices

1. **Use encrypted configuration** for sensitive credentials
2. **Implement proper validation** for all email inputs
3. **Use rate limiting** to prevent abuse
4. **Provide both HTML and text** versions of templates
5. **Test with console provider** during development
6. **Monitor email delivery** in production
7. **Handle errors gracefully** with user-friendly messages
8. **Use meaningful subject lines** and sender names

## Next Steps

- [API Reference](../../api/email.md)
- [Security Best Practices](../../security/best-practices.md)
- [Configuration Guide](../../configuration/files.md)
- [Deployment Guide](../../deployment/production.md)

The email system provides a robust foundation for all your application's communication needs while maintaining security and reliability.