Skip to content

Sending email from Quantstrip

The send_email() function

send_email(subject,body,to,account=None)

There are two ways to integrate with the email functionality in Quantstrip, either using the send_email() function or using the email_manager object for more advanced options and formatting.

The send_email() function provides a simple interface for sending emails from your trading clients. It's part of the email management system that supports multiple email accounts and handles all SMTP configuration automatically.

Key Features

  • Simple function call to send emails
  • Automatic account selection (uses default if not specified)
  • Support for multiple recipients
  • HTML email support
  • Built-in error handling and reporting

Parameters:

Parameter Type Description
subject str Email subject line
body str Email body content (plain text or HTML)
to str Recipient email address(es), comma-separated for multiple
account str Optional account name to use. Uses default account if not specified

Returns: tuple[bool, str] - (success status, message describing result)

Example:

from quantstrip import send_email

# Send with default account
success, msg = send_email(
    subject="Trade Alert",
    body="SPY position opened at $450",
    to="trader@example.com"
)

if success:
    print("Email sent successfully")
else:
    print(f"Email failed: {msg}")


Multiple Recipients

You can send to multiple recipients by comma-separating email addresses.

Example:

# Send to multiple recipients
send_email(
    subject="Daily Report",
    body="Trading summary attached",
    to="trader1@example.com,trader2@example.com,manager@example.com"
)


Using Specific Account

If you have multiple email accounts configured (e.g., one for alerts, one for reports), specify which to use with the account parameter.

Example:

# Send using specific account
send_email(
    subject="URGENT: Stop Loss Hit",
    body="Position closed at -2%",
    to="trader@example.com",
    account="Alerts"  # Use the "Alerts" account
)


Error Handling

The function returns a tuple with success status and a descriptive message. Always check the result to handle failures gracefully.

Example:

success, msg = send_email(
    subject="Trade Execution",
    body="Filled 100 AAPL @ $150",
    to="trader@example.com"
)

if not success:
    # Handle the error
    logger.error(f"Failed to send email: {msg}")
    # Possible errors:
    # - "Email account 'X' not found"
    # - "No email accounts configured"
    # - "Authentication failed - check username/password"
    # - "Could not connect to SMTP server - check server/port"


Common Use Cases

Trade Alerts

# Alert on position entry
def on_entry(self, symbol, price, quantity):
    send_email(
        subject=f"Position Opened: {symbol}",
        body=f"Bought {quantity} shares of {symbol} at ${price}",
        to="trader@example.com"
    )

Daily Reports

# Send end-of-day summary
def send_daily_report(self):
    report = self.generate_report()  # Your report logic

    send_email(
        subject=f"Daily Report - {datetime.now().strftime('%Y-%m-%d')}",
        body=report,
        to="trader@example.com,manager@example.com"
    )

Error Notifications

# Alert on strategy errors
try:
    self.execute_strategy()
except Exception as e:
    send_email(
        subject="Strategy Error!",
        body=f"Error in {self.strategy_name}:\n{str(e)}",
        to="trader@example.com",
        account="Alerts"  # Use high-priority account
    )

Stop Loss Alerts

# Urgent notifications
def on_stop_loss(self, symbol, loss_amount):
    send_email(
        subject=f"STOP LOSS: {symbol}",
        body=f"Stop loss triggered on {symbol}. Loss: ${loss_amount:.2f}",
        to="trader@example.com",
        account="Alerts"
    )

Using the email_manager object

The email_manager object can be used directly for more advanced options like sending HTML formatted emails.

Sending HTML Emails

For HTML formatted emails, use the underlying email_manager.send() function with html=True.

Example:

from quantstrip import email_manager

html_body = """
<html>
<body>
    <h2>Trade Summary</h2>
    <p>Today's P&L: <span style="color:green">$1,234.56</span></p>
    <ul>
        <li>AAPL: +$500</li>
        <li>MSFT: +$734.56</li>
    </ul>
</body>
</html>
"""

success, msg = email_manager.send(
    subject="Daily P&L Report",
    body=html_body,
    to="trader@example.com",
    html=True
)


Configuration

Before using send_email(), you need to configure at least one email account in your settings. Email accounts are managed through the EmailManager class and stored in the settings system.

Account Setup

Email accounts are configured at: /config/Notification/Email Accounts/[AccountName]/

Each account requires:

Field Description
smtp_server SMTP server address (e.g., smtp.gmail.com)
smtp_port SMTP port (typically 587 for TLS)
use_tls Whether to use TLS encryption (true/false)
username SMTP username
password SMTP password (stored securely)
from_address Email address to send from
from_name Display name for sender
is_default Whether this is the default account (true/false)

Provider Templates

The EmailManager includes templates for common providers:

  • Gmail: smtp.gmail.com:587 (requires App Password)
  • Outlook: smtp.office365.com:587
  • Yahoo: smtp.mail.yahoo.com:587 (requires App Password)
  • SendGrid: smtp.sendgrid.net:587

Use these templates when creating accounts programmatically.


Testing Configuration

Always test your email configuration before relying on it in production.

from email_manager import email_manager

# Test an account
success, msg = email_manager.test_account(
    name="Default",
    test_recipient="your.email@example.com"
)

if success:
    print("Email configuration working!")
else:
    print(f"Configuration problem: {msg}")


Best Practices

Batching Notifications

Instead of sending an email for every event, batch them together.

class NotificationBatcher:
    def __init__(self, flush_interval_seconds=300):
        self.messages = []
        self.last_flush = datetime.now()
        self.flush_interval = timedelta(seconds=flush_interval_seconds)

    def add_message(self, message):
        self.messages.append(f"[{datetime.now().strftime('%H:%M:%S')}] {message}")

        # Auto-flush if interval passed
        if datetime.now() - self.last_flush > self.flush_interval:
            self.flush()

    def flush(self):
        if self.messages:
            body = "\n".join(self.messages)
            send_email(
                subject=f"Trading Updates ({len(self.messages)} events)",
                body=body,
                to="trader@example.com"
            )
            self.messages.clear()
            self.last_flush = datetime.now()

# Usage
batcher = NotificationBatcher(flush_interval_seconds=300)  # 5 minutes

# Throughout trading day
batcher.add_message("Opened AAPL position")
batcher.add_message("Stop loss adjusted for MSFT")
# ... messages accumulate ...

# On shutdown or at regular intervals
batcher.flush()


Troubleshooting

Authentication Failed

Error: "Authentication failed - check username/password"
Solution: For Gmail/Yahoo, use App Passwords instead of account passwords. Enable 2FA first, then generate an app-specific password.

Connection Errors

Error: "Could not connect to SMTP server - check server/port"
Solution: Verify your SMTP server and port. Most providers use port 587 with TLS.

Account Not Found

Error: "Email account 'X' not found"
Solution: Check that the account name matches exactly (case-sensitive). Use email_manager.get_accounts() to list available accounts.

No Accounts Configured

Error: "No email accounts configured"
Solution: Create at least one email account before calling send_email().


Debugging

Enable detailed logging to troubleshoot email issues:

import logging

# Enable email manager debug logging
logging.getLogger('email_manager').setLevel(logging.DEBUG)

# Your code
success, msg = send_email("Test", "Body", "test@example.com")
print(f"Result: {success}, Message: {msg}")