Mail Integration
The Nexios Mail contrib module provides a comprehensive email sending solution with SMTP support, template integration, and background task processing.
Overview
Nexios Mail is a powerful and easy-to-use email sending solution for Nexios applications that includes:
- SMTP Support: Full SMTP configuration with TLS/SSL support
- Template Integration: Jinja2-based HTML email templates
- Background Tasks: Async email sending with nexios-contrib tasks
- Dependency Injection: Easy integration with Nexios applications
- Multiple Providers: Pre-configured settings for Gmail, Outlook, SendGrid
- Attachments: Support for file attachments and inline images
- Error Handling: Comprehensive error reporting and logging
Installation
# Basic installation
pip install nexios-contrib[mail]
# With template support
pip install nexios-contrib[mail,templating]
# With all features
pip install nexios-contrib[all]Direct MailClient Usage
The most straightforward way to send emails is by using the MailClient class directly. This approach gives you full control over the email sending process without requiring dependency injection.
Creating a MailClient
from nexios_contrib.mail import MailClient, MailConfig
# Create with default configuration (uses environment variables)
mail_client = MailClient()
# Or with explicit configuration
config = MailConfig(
smtp_host="smtp.gmail.com",
smtp_port=587,
smtp_username="your-email@gmail.com",
smtp_password="your-app-password",
use_tls=True,
default_from="Your Name <your-email@gmail.com>"
)
mail_client = MailClient(config=config)Basic Email Sending
import asyncio
async def send_basic_email():
# Start the client (establishes SMTP connection)
await mail_client.start()
try:
# Send a simple email
result = await mail_client.send_email(
to="recipient@example.com",
subject="Hello World",
body="This is a plain text email",
html_body="<h1>Hello World</h1><p>This is an HTML email.</p>"
)
if result.success:
print(f"Email sent successfully! Message ID: {result.message_id}")
else:
print(f"Failed to send email: {result.error}")
finally:
# Always stop the client to close connections
await mail_client.stop()
# Run the async function
asyncio.run(send_basic_email())Using Templates
Create templates in your templates/emails/ directory:
templates/emails/welcome.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome {{ name }}!</title>
</head>
<body>
<h1>Welcome {{ name }}!</h1>
<p>Thank you for joining {{ company_name }}.</p>
<p>Your account has been created with email: {{ email }}</p>
<a href="{{ activation_url }}">Activate Your Account</a>
</body>
</html>templates/emails/welcome.txt
Welcome {{ name }}!
Thank you for joining {{ company_name }}.
Your account has been created with email: {{ email }}.
Activate Your Account: {{ activation_url }}Send template emails:
async def send_template_email():
config = MailConfig(
smtp_host="smtp.gmail.com",
smtp_port=587,
smtp_username="your-email@gmail.com",
smtp_password="your-app-password",
use_tls=True,
template_directory="templates/emails"
)
mail_client = MailClient(config=config)
await mail_client.start()
try:
result = await mail_client.send_template_email(
to="newuser@example.com",
subject="Welcome to Our Platform!",
template_name="welcome",
context={
"name": "John Doe",
"email": "newuser@example.com",
"company_name": "Acme Corp",
"activation_url": "https://example.com/activate/12345"
}
)
print(f"Template email sent: {result.success}")
finally:
await mail_client.stop()
asyncio.run(send_template_email())Advanced Message Creation
For more control, create EmailMessage objects directly:
from nexios_contrib.mail import EmailMessage
async def send_advanced_email():
config = MailConfig(
smtp_host="smtp.gmail.com",
smtp_port=587,
smtp_username="your-email@gmail.com",
smtp_password="your-app-password",
use_tls=True
)
mail_client = MailClient(config=config)
await mail_client.start()
try:
# Create a detailed email message
message = EmailMessage(
to="recipient@example.com",
subject="Advanced Email",
body="Plain text content",
html_body="<h1>HTML Content</h1>",
cc="manager@example.com",
bcc="archive@example.com"
)
# Add custom headers
message.add_header("X-Campaign-ID", "summer-2024")
message.add_header("X-Mailer", "Nexios Mail")
# Add attachments
message.add_attachment("report.pdf", b"PDF content", "application/pdf")
# Send the message
result = await mail_client.send_message(message)
print(f"Advanced email sent: {result.success}")
finally:
await mail_client.stop()
asyncio.run(send_advanced_email())Integration with Nexios Applications
While direct MailClient usage is simple, integrating with Nexios applications provides additional benefits like automatic lifecycle management and dependency injection.
Application Setup
For Nexios applications, use the setup_mail function for automatic lifecycle management:
from nexios import NexiosApp
from nexios_contrib.mail import setup_mail, MailConfig
app = NexiosApp()
# Setup with environment variables
mail_client = setup_mail(app)
# Or with custom configuration
config = MailConfig(
smtp_host="smtp.gmail.com",
smtp_port=587,
smtp_username="your-email@gmail.com",
smtp_password="your-app-password",
use_tls=True,
default_from="Your Name <your-email@gmail.com>"
)
mail_client = setup_mail(app, config=config)Environment Variables
# SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_USE_TLS=true
SMTP_USE_SSL=false
# Email Defaults
MAIL_DEFAULT_FROM=Your Name <your-email@gmail.com>
MAIL_DEFAULT_REPLY_TO=support@yourcompany.com
# Template Directory
MAIL_TEMPLATE_DIR=templates/emails
# Debug Settings
MAIL_DEBUG=false
MAIL_SUPPRESS_SEND=falseDependency Injection
For cleaner code in your route handlers, use dependency injection:
from nexios.http import Request, Response
from nexios_contrib.mail import MailDepend
@app.post("/send-email")
async def send_email(
request: Request,
response: Response,
mail_client: MailClient = MailDepend()
):
result = await mail_client.send_email(
to="user@example.com",
subject="Welcome to Our Service",
body="Thank you for joining our platform!",
html_body="<h1>Welcome!</h1><p>Thank you for joining our platform!</p>"
)
return response.json({
"success": result.success,
"message_id": result.message_id,
"sent_at": result.sent_at.isoformat()
})Getting MailClient from Request
Alternatively, get the mail client directly from the request:
from nexios_contrib.mail import get_mail_from_request
@app.post("/send-email-manual")
async def send_email_manual(request: Request, response: Response):
mail_client = get_mail_from_request(request)
result = await mail_client.send_email(
to="user@example.com",
subject="Welcome to Our Service",
body="Thank you for joining our platform!"
)
return response.json({"success": result.success, "message_id": result.message_id})Background Email Sending
Send emails asynchronously without blocking your API responses:
from nexios_contrib.mail import send_email_async
@app.post("/send-async")
async def send_async_email(
request: Request,
response: Response
):
task = await send_email_async(
request=request,
to="user@example.com",
subject="Processing Your Request",
body="We're processing your request and will notify you when complete."
)
return response.json({
"message": "Email queued for sending",
"task_id": task.id if task else None
})Configuration
Provider-Specific Configurations
Gmail
config = MailConfig.for_gmail(
username="your-email@gmail.com",
password="your-app-password", # Use app password, not regular password
default_from="Your Name <your-email@gmail.com>"
)Outlook/Office 365
config = MailConfig.for_outlook(
username="your-email@outlook.com",
password="your-password",
default_from="Your Name <your-email@outlook.com>"
)SendGrid
config = MailConfig.for_sendgrid(
api_key="your-sendgrid-api-key",
default_from="your-email@yourdomain.com"
)Advanced Features
Custom Email Messages
from nexios_contrib.mail import EmailMessage
# Create detailed email message
message = EmailMessage(
to="recipient@example.com",
subject="Custom Email",
body="Plain text content",
html_body="<h1>HTML Content</h1>",
cc="manager@example.com",
bcc="archive@example.com",
priority=1 # High priority
)
# Add custom headers
message.add_header("X-Campaign-ID", "summer-2024")
message.add_header("X-Mailer", "Nexios Mail")
# Add attachments
message.add_attachment("report.pdf", b"PDF content", "application/pdf")
# Send the message
result = await mail_client.send_message(message)Template Custom Filters
# Add custom Jinja2 filters
def format_currency(value, currency="USD"):
return f"{value:.2f} {currency}"
# In your mail client setup
mail_client._template_env.filters["currency"] = format_currency
# Use in templates
{{ price | currency }}API Reference
MailClient
The main mail client class for sending emails.
Methods
send_email(to, subject, body=None, html_body=None, **kwargs)- Send an emailsend_message(message)- Send an EmailMessage objectsend_template_email(to, subject, template_name, context=None, **kwargs)- Send template emailcreate_message(to, subject, **kwargs)- Create EmailMessage object
EmailMessage
Represents an email message with all its components.
Properties
to- Recipient email addressessubject- Email subjectbody- Plain text bodyhtml_body- HTML bodyattachments- List of attachmentsheaders- Custom headers
Methods
add_attachment(filename, content, content_type=None, content_id=None)- Add attachmentset_template(template_name, context=None)- Set templateadd_header(name, value)- Add custom header
MailConfig
Configuration for the mail client.
Class Methods
for_gmail(username, password, **kwargs)- Gmail configurationfor_outlook(username, password, **kwargs)- Outlook configurationfor_sendgrid(api_key, **kwargs)- SendGrid configuration
Best Practices
Security
- Never hardcode credentials - Always use environment variables
- Use app passwords - For Gmail, generate app passwords instead of using your main password
- Enable TLS - Always use TLS/SSL for secure connections
- Validate inputs - Sanitize and validate all email inputs
Performance
- Use background tasks - Send emails asynchronously to avoid blocking responses
- Connection pooling - Reuse SMTP connections when possible
- Template caching - Templates are automatically cached for performance
Reliability
- Error handling - Always handle email sending errors gracefully
- Logging - Enable debug mode during development
- Testing - Use
suppress_send=Truefor testing without actually sending emails
Troubleshooting
Common Issues
Authentication Failed
- Check SMTP credentials
- For Gmail, use an App Password instead of your regular password
- Verify 2FA settings
Connection Timeout
- Check SMTP host and port
- Verify firewall settings
- Increase
smtp_timeoutvalue
Template Not Found
- Verify template directory path
- Check template file names and extensions
- Ensure template files exist
Background Tasks Not Working
- Install nexios-contrib tasks:
pip install nexios-contrib[tasks] - Setup tasks in your app:
setup_tasks(app)
- Install nexios-contrib tasks:
Debug Mode
Enable debug mode to see SMTP communication:
config = MailConfig(
debug=True, # Enables SMTP debug logging
suppress_send=True # Test mode - don't actually send
)Integration with Other Modules
Background Tasks
The mail module integrates seamlessly with the nexios-contrib tasks module for async email sending:
from nexios_contrib.tasks import setup_tasks
from nexios_contrib.mail import setup_mail
app = NexiosApp()
# Setup tasks first
task_manager = setup_tasks(app)
# Then setup mail (will automatically integrate with tasks)
mail_client = setup_mail(app)Templates
The mail module uses Jinja2 for template rendering, which can be integrated with your existing template setup:
# Share template environment with your web templates
from jinja2 import FileSystemLoader, Environment
# Create shared template environment
template_env = Environment(
loader=FileSystemLoader(["templates/web", "templates/emails"])
)
# Use with mail client
mail_client._template_env = template_envExamples
Complete Email Service
from nexios import NexiosApp
from nexios_contrib.mail import setup_mail, MailConfig, MailDepend
from nexios_contrib.tasks import setup_tasks
import os
app = NexiosApp()
# Setup background tasks
task_manager = setup_tasks(app)
# Setup mail
config = MailConfig(
smtp_host=os.getenv("SMTP_HOST"),
smtp_port=int(os.getenv("SMTP_PORT")),
smtp_username=os.getenv("SMTP_USERNAME"),
smtp_password=os.getenv("SMTP_PASSWORD"),
use_tls=True,
default_from=os.getenv("MAIL_DEFAULT_FROM"),
template_directory="templates/emails"
)
mail_client = setup_mail(app, config=config)
@app.post("/send-welcome")
async def send_welcome_email(
request: Request,
response: Response,
mail_client: MailClient = MailDepend()
):
data = await request.json
result = await mail_client.send_template_email(
to=data["email"],
subject="Welcome to Our Platform!",
template_name="welcome",
context={
"name": data["name"],
"email": data["email"],
"company_name": "Acme Corp"
}
)
return response.json({
"success": result.success,
"message_id": result.message_id,
"error": result.error
})
@app.post("/send-async")
async def send_async_email(
request: Request,
response: Response
):
data = await request.json
task = await send_email_async(
request=request,
to=data["email"],
subject=data["subject"],
body=data["body"]
)
return response.json({
"message": "Email queued for sending",
"task_id": task.id if task else None
})This comprehensive mail integration provides everything you need to add professional email functionality to your Nexios applications with ease.
