A Python package for sending emails using any SMTP server with STARTTLS support
Project description
MailWorks
A Python package for sending emails using any SMTP server with STARTTLS support. This package provides a simple, secure, and reliable way to send emails through any email provider including Gmail, Outlook, Yahoo, and more. Defaults to Gmail for convenience.
Features
- ✅ Universal SMTP Support - Works with any SMTP provider (Gmail, Outlook, Yahoo, ProtonMail, etc.)
- ✅ STARTTLS Security - Secure email transmission with TLS encryption
- ✅ Gmail Defaults - Pre-configured for Gmail, works out of the box
- ✅ Support for plain text and HTML emails
- ✅ File attachments
- ✅ Multiple recipients
- ✅ Environment variable configuration
- ✅ Configuration file support
- ✅ Connection testing
- ✅ Comprehensive error handling
- ✅ No external dependencies (uses Python standard library only)
- ✅ Backward compatibility (GmailSender alias available)
Installation
From source (development)
# Clone the repository
git clone https://github.com/antoniocostabr/mailworks.git
cd mailworks
# Install in development mode
pip install -e .
# Or install with development dependencies
pip install -e ".[dev]"
From PyPI (when published)
pip install mailworks
Supported Email Providers
MailWorks supports any email provider that offers SMTP with STARTTLS encryption:
| Provider | SMTP Server | Port | Notes |
|---|---|---|---|
| Gmail | smtp.gmail.com | 587 | Default configuration |
| Outlook/Hotmail | smtp-mail.outlook.com | 587 | Microsoft email services |
| Yahoo | smtp.mail.yahoo.com | 587 | Requires app password |
| ProtonMail | mail.protonmail.ch | 587 | Secure email provider |
| Zoho | smtp.zoho.com | 587 | Business email |
| SendGrid | smtp.sendgrid.net | 587 | Email delivery service |
| Amazon SES | email-smtp.region.amazonaws.com | 587 | AWS email service |
| Internal/Corporate | mail.company.com | 25/587 | No authentication required |
| Custom | your.smtp.server | 587 | Any SMTP server with STARTTLS |
Gmail Setup (if using Gmail)
For Gmail users, you need to set up App Passwords:
Step 1: Enable 2-Factor Authentication
- Go to Google Account settings
- Navigate to "Security" > "2-Step Verification"
- Enable 2-Step Verification if not already enabled
Step 2: Generate App Password
- Go to Google Account settings
- Navigate to "Security" > "2-Step Verification" > "App passwords"
- Select "Mail" and your device
- Generate the app password
- Important: Use this 16-character app password, not your regular Gmail password
Quick Start
Basic Usage (Gmail - Default)
from mailworks import MailSender
# Using environment variables (Gmail defaults)
# Set environment variables:
# export EMAIL="your.email@gmail.com"
# export PASSWORD="your_app_password"
sender = MailSender()
# Send a simple email
success = sender.send_simple_email(
to_email="recipient@example.com",
subject="Hello from Python!",
message="This is a test email sent from Python."
)
if success:
print("Email sent successfully!")
Using Other Email Providers
from mailworks import MailSender
# Outlook/Hotmail
sender = MailSender(
email="your.email@outlook.com",
password="your_password",
smtp_server="smtp-mail.outlook.com",
smtp_port=587
)
# Yahoo
sender = MailSender(
email="your.email@yahoo.com",
password="your_app_password",
smtp_server="smtp.mail.yahoo.com",
smtp_port=587
)
# Custom SMTP server
sender = MailSender(
email="your.email@yourdomain.com",
password="your_password",
smtp_server="mail.yourdomain.com",
smtp_port=587
)
Internal/Corporate SMTP Servers (No Authentication)
For internal corporate SMTP servers that don't require authentication:
⚠️ Security Note: Authentication is enabled by default for security. Only disable it (
auth_required=False) for trusted internal SMTP servers within your corporate network.
from mailworks import MailSender
# Corporate SMTP server without authentication
sender = MailSender(
email="noreply@company.com",
smtp_server="mail.company.com",
smtp_port=25, # Common for internal servers
auth_required=False # Disable authentication
)
# Environment variables approach
# export EMAIL="noreply@company.com"
# export SMTP_SERVER="mail.company.com"
# export SMTP_PORT="25"
# export AUTH_REQUIRED="false"
sender = MailSender()
# Send HTML email with attachments to multiple recipients
success = sender.send_email(
to_emails=["recipient1@example.com", "recipient2@example.com"],
subject="Advanced Email Example",
message="Plain text version of the email.",
html_message="""
<html>
<body>
<h2>Hello!</h2>
<p>This is an <b>HTML email</b> with formatting.</p>
</body>
</html>
""",
attachments=["document.pdf", "image.png"]
)
Configuration Options
1. Environment Variables (Recommended)
Set these environment variables:
# Required
export EMAIL="your.email@anyprovider.com"
export PASSWORD="your_app_password" # Not required if AUTH_REQUIRED=false
# Optional (defaults to Gmail if not specified)
export SMTP_SERVER="smtp.anyprovider.com"
export SMTP_PORT="587"
export AUTH_REQUIRED="true" # Set to "false" for servers without authentication
2. Configuration File
Create a config file (e.g., email_config.txt):
EMAIL=your.email@anyprovider.com
PASSWORD=your_app_password
SMTP_SERVER=smtp.anyprovider.com
SMTP_PORT=587
AUTH_REQUIRED=true
Use it in your code:
from mailworks.config import ConfigManager
config_manager = ConfigManager.from_file("email_config.txt")
sender = MailSender(
email=config_manager.config.email,
password=config_manager.config.password,
smtp_server=config_manager.config.smtp_server,
smtp_port=config_manager.config.smtp_port
)
3. Direct Parameters
from mailworks import MailSender
# Any SMTP provider
sender = MailSender(
email="your.email@anyprovider.com",
password="your_password",
smtp_server="smtp.anyprovider.com",
smtp_port=587
)
# Gmail (using defaults)
sender = MailSender(
email="your.email@gmail.com",
password="your_app_password"
)
API Reference
MailSender Class
Constructor
MailSender(email=None, password=None, smtp_server=None, smtp_port=None, auth_required=None)
email(str, optional): Email address. If not provided, reads fromEMAILenvironment variable.password(str, optional): Email password/app password. If not provided, reads fromPASSWORDenvironment variable. Not required ifauth_required=False.smtp_server(str, optional): SMTP server address. If not provided, reads fromSMTP_SERVERenvironment variable or defaults to Gmail.smtp_port(int, optional): SMTP port number. If not provided, reads fromSMTP_PORTenvironment variable or defaults to 587.auth_required(bool, optional): Whether SMTP authentication is required. Defaults toTruefor security. If not provided, reads fromAUTH_REQUIREDenvironment variable or defaults toTrue. Set toFalseonly for trusted internal SMTP servers.
Methods
send_email(to_emails, subject, message, html_message=None, attachments=None)
Send an email with advanced options.
Parameters:
to_emails(str or list): Recipient email address(es)subject(str): Email subjectmessage(str): Plain text message bodyhtml_message(str, optional): HTML message bodyattachments(list, optional): List of file paths to attach
Returns: bool - True if successful
send_simple_email(to_email, subject, message)
Send a simple text email to a single recipient.
Parameters:
to_email(str): Recipient email addresssubject(str): Email subjectmessage(str): Plain text message body
Returns: bool - True if successful
test_connection()
Test the connection to the configured SMTP server.
Returns: bool - True if connection successful
GmailSender Class (Backward Compatibility)
For backward compatibility, GmailSender is available as an alias to MailSender:
from mailworks import GmailSender # Same as MailSender
sender = GmailSender(email="your@gmail.com", password="app_password")
Exception Classes
EmailSenderError: Base exception classAuthenticationError: Raised when SMTP authentication failsSendError: Raised when email sending failsConfigurationError: Raised when configuration is invalid
Examples
See the examples/ directory for complete working examples:
basic_example.py: Simple email sending using environment variablesadvanced_example.py: HTML emails with attachments and multiple recipientssmtp_providers_example.py: Examples for different email providersinternal_smtp_example.py: Using internal/corporate SMTP servers without authenticationconfig_example.py: Different configuration methods
Error Handling
from mailworks import MailSender, AuthenticationError, SendError
try:
sender = MailSender()
sender.test_connection()
success = sender.send_simple_email(
to_email="recipient@example.com",
subject="Test Email",
message="Hello, World!"
)
except AuthenticationError as e:
print(f"Authentication failed: {e}")
print("Check your email and password")
except SendError as e:
print(f"Failed to send email: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Security Best Practices
-
Use App Passwords: Never use your regular Gmail password. Always use Gmail App Passwords.
-
Environment Variables: Store credentials in environment variables, not in your code.
-
Config Files: If using config files, add them to
.gitignoreto avoid committing credentials. -
Permissions: Keep your app passwords secure and rotate them regularly.
Common Issues & Solutions
Authentication Error (535)
Problem: smtplib.SMTPAuthenticationError: (535, '5.7.8 Username and Password not accepted')
Solutions:
- Ensure you're using an App Password, not your regular Gmail password
- Check that 2-Factor Authentication is enabled on your Gmail account
- Verify the email address is correct
- Try generating a new App Password
Connection Issues
Problem: Connection timeouts or failures
Solutions:
- Check your internet connection
- Ensure port 587 is not blocked by your firewall
- Try using a different network
- Verify SMTP server settings for your provider
File Attachment Issues
Problem: Attachments not working
Solutions:
- Check that file paths exist and are accessible
- Ensure files are not too large (most providers have limits like 25MB for Gmail)
- Verify file permissions
Migration Guide
From v1.x (GmailSender only)
If you were using the old Gmail-only version:
# Old way (still works)
from mailworks import GmailSender
sender = GmailSender(email="user@gmail.com", password="password")
# New recommended way
from mailworks import MailSender
sender = MailSender(email="user@gmail.com", password="password")
Environment Variables
# Old variables (still supported for backward compatibility)
export GMAIL_EMAIL="your.email@gmail.com"
export GMAIL_PASSWORD="your_app_password"
# New recommended variables
export EMAIL="your.email@anyprovider.com"
export PASSWORD="your_app_password"
export SMTP_SERVER="smtp.anyprovider.com" # Optional
export SMTP_PORT="587" # Optional
Development
Running Examples
# Set your credentials
export EMAIL="your.email@anyprovider.com"
export PASSWORD="your_app_password"
# Run examples
python examples/basic_example.py
python examples/advanced_example.py
python examples/config_example.py
Testing
# Install development dependencies
pip install -e ".[dev]"
# Run tests (when available)
pytest
# Code formatting
black mailworks/
black examples/
# Type checking
mypy mailworks/
What's New in v2.0
🎉 Universal SMTP Support: No longer limited to Gmail! Now works with any email provider.
Key Improvements:
- ✅ Any SMTP Provider: Gmail, Outlook, Yahoo, ProtonMail, custom servers, etc.
- ✅ Clean Package Name:
mailworksinstead ofemail_sender - ✅ Better Class Names:
MailSenderinstead ofGmailSender - ✅ Simplified Configuration: Generic environment variables (
EMAIL,PASSWORD) - ✅ Backward Compatible: Existing code continues to work
- ✅ Enhanced Documentation: Comprehensive examples for all providers
Quick Comparison:
# v1.x - Gmail only
from email_sender import GmailSender
sender = GmailSender(email="user@gmail.com", password="password")
# v2.x - Any provider
from mailworks import MailSender
sender = MailSender(
email="user@outlook.com",
password="password",
smtp_server="smtp-mail.outlook.com",
smtp_port=587
)
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a detailed history of changes and version information.
Support
If you encounter any issues or have questions:
- Check the Common Issues section
- Look at the examples for usage patterns
- Open an issue on GitHub
v1.0.0
- Initial release
- Gmail SMTP support
- HTML email support
- File attachments
- Multiple recipients
- Configuration management
- Comprehensive error handling
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mailworks-2.1.0.tar.gz.
File metadata
- Download URL: mailworks-2.1.0.tar.gz
- Upload date:
- Size: 15.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9ac48ba9d30a36e196f3816414bf29228a117631e07dd215dc5c6b1a3fdff1c
|
|
| MD5 |
6f1ab1c524514678652fa5c7374303b5
|
|
| BLAKE2b-256 |
777e2407d71a3a4ce74aa084806956c40cc873395ee213f5887fc315dc92448f
|
File details
Details for the file mailworks-2.1.0-py3-none-any.whl.
File metadata
- Download URL: mailworks-2.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4642ee112eb921e116a653781606b93141d33e15b11c662cd607d58c63b1cb3
|
|
| MD5 |
d6e8f26c99d1fc50fd622fb13c92d311
|
|
| BLAKE2b-256 |
c07ea2b61fe2525e8e6d270838ca3106439f34bae73d8c4c309f82a4b9c4c4d9
|