function send_email
Sends templated emails to one or more recipients using either MS365 or SMTP provider based on configuration, with support for CC, BCC, and attachments.
/tf/active/vicechatdev/CDocs single class/utils/notifications.py
569 - 641
moderate
Purpose
This function provides a unified interface for sending emails in the application, abstracting away the underlying email provider (MS365 or SMTP). It handles template rendering with dynamic data, automatic conversion to plain text, address normalization, and error handling. The function is designed to be used throughout the application for all email notifications, including user notifications, document reviews, approvals, and system alerts.
Source Code
def send_email(to_addresses: Union[str, List[str]],
subject: str,
template_name: str,
template_data: Dict[str, Any] = None,
cc_addresses: Union[str, List[str]] = None,
bcc_addresses: Union[str, List[str]] = None,
attachments: List[Dict[str, Any]] = None) -> bool:
"""
Send email using configured method (MS365 or SMTP).
Args:
to_addresses: Recipient email address(es)
subject: Email subject
template_name: Name of email template to use
template_data: Data to populate the template
cc_addresses: Optional CC recipient(s)
bcc_addresses: Optional BCC recipient(s)
attachments: Optional list of attachments
Returns:
Boolean indicating success
"""
try:
# Convert single addresses to lists
if isinstance(to_addresses, str):
to_addresses = [to_addresses]
if isinstance(cc_addresses, str):
cc_addresses = [cc_addresses]
if isinstance(bcc_addresses, str):
bcc_addresses = [bcc_addresses]
# Check that we have at least one recipient
if not to_addresses:
logger.error("No recipients specified")
return False
# Default template data
data = template_data or {}
data.update({
'app_name': settings.APP_NAME,
'app_url': settings.APP_URL,
'current_year': datetime.now().year,
'sender_name': settings.EMAIL_SENDER_NAME
})
# Get template content
if template_name not in EMAIL_TEMPLATES:
logger.error(f"Email template not found: {template_name}")
return False
template = EMAIL_TEMPLATES[template_name]
# Render template
body_html = render_template(template, data)
# Generate plain text version
body_text = html_to_text(body_html)
# Send email using configured method
if settings.EMAIL_PROVIDER == 'MS365':
return send_email_ms365(
to_addresses, subject, body_html, body_text,
cc_addresses, bcc_addresses, attachments
)
else:
return send_email_smtp(
to_addresses, subject, body_html, body_text,
cc_addresses, bcc_addresses, attachments
)
except Exception as e:
logger.error(f"Error sending email: {e}")
return False
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
to_addresses |
Union[str, List[str]] | - | positional_or_keyword |
subject |
str | - | positional_or_keyword |
template_name |
str | - | positional_or_keyword |
template_data |
Dict[str, Any] | None | positional_or_keyword |
cc_addresses |
Union[str, List[str]] | None | positional_or_keyword |
bcc_addresses |
Union[str, List[str]] | None | positional_or_keyword |
attachments |
List[Dict[str, Any]] | None | positional_or_keyword |
Parameter Details
to_addresses: Primary recipient email address(es). Can be a single email string or a list of email strings. At least one recipient must be provided or the function will return False.
subject: The subject line of the email. Should be a non-empty string that clearly describes the email content.
template_name: Name/key of the email template to use from the EMAIL_TEMPLATES dictionary. Must match an existing template key or the function will return False with an error logged.
template_data: Optional dictionary containing key-value pairs to populate template variables. If None, an empty dict is used. The function automatically adds 'app_name', 'app_url', 'current_year', and 'sender_name' to this data.
cc_addresses: Optional carbon copy recipient(s). Can be a single email string, a list of email strings, or None if no CC recipients are needed.
bcc_addresses: Optional blind carbon copy recipient(s). Can be a single email string, a list of email strings, or None if no BCC recipients are needed.
attachments: Optional list of attachment dictionaries. Each dictionary should contain attachment metadata (likely including 'filename', 'content', and 'content_type' keys based on typical email attachment patterns). Can be None if no attachments are needed.
Return Value
Type: bool
Returns a boolean value: True if the email was successfully sent through the configured provider (MS365 or SMTP), False if any error occurred including missing recipients, invalid template name, template rendering errors, or provider-specific sending failures. All errors are logged before returning False.
Dependencies
loggingdatetimetypingemail.mime.multipartemail.mime.textemail.mime.applicationsmtplibmsalrequestsCDocsCDocs.configCDocs.models.user_extensionsCDocs.utils
Required Imports
from typing import Union, List, Dict, Any
from datetime import datetime
import logging
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.config import settings
Condition: Required to access EMAIL_PROVIDER, APP_NAME, APP_URL, EMAIL_SENDER_NAME configuration
Required (conditional)import smtplib
Condition: Only used if settings.EMAIL_PROVIDER is not 'MS365' (SMTP fallback)
Optionalimport msal
Condition: Only used if settings.EMAIL_PROVIDER is 'MS365'
Optionalimport requests
Condition: Only used if settings.EMAIL_PROVIDER is 'MS365' for API calls
Optionalfrom email.mime.multipart import MIMEMultipart
Condition: Only used if settings.EMAIL_PROVIDER is not 'MS365' (SMTP fallback)
Optionalfrom email.mime.text import MIMEText
Condition: Only used if settings.EMAIL_PROVIDER is not 'MS365' (SMTP fallback)
Optionalfrom email.mime.application import MIMEApplication
Condition: Only used if settings.EMAIL_PROVIDER is not 'MS365' and attachments are provided
OptionalUsage Example
# Basic usage with single recipient
success = send_email(
to_addresses='user@example.com',
subject='Welcome to Our Application',
template_name='welcome_email',
template_data={'user_name': 'John Doe'}
)
# Advanced usage with multiple recipients and attachments
success = send_email(
to_addresses=['user1@example.com', 'user2@example.com'],
subject='Document Review Required',
template_name='review_notification',
template_data={
'document_name': 'Q4 Report',
'reviewer_name': 'Jane Smith',
'due_date': '2024-01-15'
},
cc_addresses='manager@example.com',
bcc_addresses=['audit@example.com', 'compliance@example.com'],
attachments=[
{
'filename': 'report.pdf',
'content': pdf_bytes,
'content_type': 'application/pdf'
}
]
)
if success:
print('Email sent successfully')
else:
print('Failed to send email - check logs for details')
Best Practices
- Always check the return value to verify email was sent successfully before proceeding with dependent operations
- Ensure EMAIL_TEMPLATES dictionary is populated with all required templates before calling this function
- Validate email addresses before passing to this function to avoid silent failures
- Use meaningful template_name values that clearly indicate the email purpose
- Keep template_data keys consistent with template variable names to avoid rendering errors
- Configure appropriate logging to capture email sending failures for debugging
- Test both MS365 and SMTP configurations if your application supports multiple providers
- Be cautious with BCC addresses for privacy/compliance reasons - document their usage
- Consider rate limiting when sending bulk emails to avoid provider throttling
- Ensure attachments are properly formatted with required keys (filename, content, content_type)
- The function automatically adds standard template variables (app_name, app_url, current_year, sender_name) so avoid conflicts in template_data
- Single string addresses are automatically converted to lists, but providing lists is more explicit and recommended for multiple recipients
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function gen_send_email 95.6% similar
-
function send_email_ms365 78.0% similar
-
function send_email_smtp 77.9% similar
-
function send_email_ms365_v1 77.7% similar
-
function send_test_email 59.0% similar