torii-mailer

Crates.iotorii-mailer
lib.rstorii-mailer
version0.5.1
created_at2025-07-18 04:15:12.102009+00
updated_at2025-07-23 00:20:07.280489+00
descriptionPluggable email system for the torii authentication ecosystem
homepage
repositoryhttps://github.com/cmackenzie1/torii-rs
max_upload_size
id1758584
size103,358
Cole Mackenzie (cmackenzie1)

documentation

README

Torii Mailer

A pluggable email system for the Torii authentication ecosystem, built on top of lettre and askama.

Features

  • Multiple Transports: SMTP, Sendmail, and File (for local development)
  • Template Engine: Built-in askama templates with customization support
  • Pre-built Email Types: Magic links, welcome emails, password resets, etc.
  • Environment Configuration: Easy setup through environment variables
  • Local Development Friendly: File transport saves emails as .eml files
  • Type Safe: Leverages Rust's type system for email construction

Quick Start

use torii_mailer::prelude::*;

// Configure from environment variables
let config = MailerConfig::from_env()?;
let transport = config.build_transport()?;
let engine = AskamaTemplateEngine::new();

// Create template context
let context = TemplateContext {
    app_name: "My App".to_string(),
    app_url: "https://myapp.com".to_string(),
    user_name: Some("John Doe".to_string()),
    user_email: Some("john@example.com".to_string()),
};

// Build and send a magic link email
let email = MagicLinkEmail::build(
    &engine,
    &config.get_from_address(),
    "john@example.com",
    "https://myapp.com/auth/magic/abc123",
    context
).await?;

transport.send_email(email).await?;

Configuration

Configure the mailer using environment variables:

SMTP Transport

MAILER_SMTP_HOST=smtp.gmail.com
MAILER_SMTP_PORT=587
MAILER_SMTP_USERNAME=your-email@gmail.com
MAILER_SMTP_PASSWORD=your-app-password
MAILER_SMTP_TLS=starttls  # none, starttls, tls

File Transport (Development)

MAILER_FILE_OUTPUT_DIR=./emails

Sendmail Transport

MAILER_SENDMAIL=true
MAILER_SENDMAIL_COMMAND=/usr/sbin/sendmail  # optional

Common Settings

MAILER_FROM_ADDRESS=noreply@myapp.com
MAILER_FROM_NAME="My App"
MAILER_APP_NAME="My App"
MAILER_APP_URL=https://myapp.com

Built-in Email Types

The crate provides pre-built email types for common authentication flows:

  • MagicLinkEmail: Passwordless authentication links
  • WelcomeEmail: User signup confirmation
  • PasswordResetEmail: Password reset requests
  • PasswordChangedEmail: Password change notifications

Templates

Templates are built using askama and can be customized by implementing your own template engine or extending the existing ones.

Built-in Templates

All built-in templates are responsive and follow email best practices:

  • Clean, minimal design
  • Mobile-friendly layout
  • Accessible color contrast
  • Clear call-to-action buttons

Custom Templates

You can create custom templates by implementing the TemplateEngine trait or by extending the AskamaTemplateEngine.

Local Development

For local development, use the file transport which saves emails as .eml files:

let config = MailerConfig {
    transport: TransportConfig::File {
        output_dir: PathBuf::from("./emails"),
    },
    // ... other config
};

You can then open the .eml files in your email client to preview the emails.

Integration with Torii Core

The mailer integrates seamlessly with torii-core services:

use torii_core::services::MagicLinkService;
use torii_mailer::prelude::*;

// In your magic link service
let config = MailerConfig::from_env()?;
let transport = config.build_transport()?;
let engine = AskamaTemplateEngine::new();

// Generate magic link token
let token = magic_link_service.generate_token("user@example.com").await?;

// Send email
let context = TemplateContext {
    app_name: config.app_name.clone(),
    app_url: config.app_url.clone(),
    user_email: Some("user@example.com".to_string()),
    user_name: None,
};

let email = MagicLinkEmail::build(
    &engine,
    &config.get_from_address(),
    "user@example.com",
    &format!("{}/auth/magic/{}", config.app_url, token.token),
    context
).await?;

transport.send_email(email).await?;
Commit count: 149

cargo fmt