107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
from typing import List, Union
|
|
from django.core.mail import send_mail, EmailMessage
|
|
from django.contrib.auth import get_user_model
|
|
from django.template.loader import render_to_string
|
|
from django.conf import settings # To access EMAIL_HOST_USER, etc.
|
|
|
|
UserModel = get_user_model()
|
|
User = UserModel # Type alias for clarity
|
|
|
|
class EmailService:
|
|
"""
|
|
A service class for sending single or bulk emails.
|
|
"""
|
|
|
|
def _send_email_internal(
|
|
self,
|
|
subject: str,
|
|
body: str,
|
|
recipient_list: List[str],
|
|
from_email: str = settings.DEFAULT_FROM_EMAIL,
|
|
html_content: Union[str, None] = None
|
|
) -> int:
|
|
"""
|
|
Internal method to handle the actual sending using Django's email backend.
|
|
"""
|
|
try:
|
|
# Using EmailMessage for more control (e.g., HTML content)
|
|
email = EmailMessage(
|
|
subject=subject,
|
|
body=body,
|
|
from_email=from_email,
|
|
to=recipient_list,
|
|
)
|
|
|
|
if html_content:
|
|
email.content_subtype = "html" # Main content is HTML
|
|
email.body = html_content # Overwrite body with HTML
|
|
|
|
# Returns the number of successfully sent emails (usually 1 or the count of recipients)
|
|
sent_count = email.send(fail_silently=False)
|
|
return sent_count
|
|
|
|
except Exception as e:
|
|
# Log the error (in a real app, use Django's logger)
|
|
print(f"Error sending email to {recipient_list}: {e}")
|
|
return 0
|
|
|
|
|
|
def send_single_email(
|
|
self,
|
|
user: User,
|
|
subject: str,
|
|
template_name: str,
|
|
context: dict,
|
|
from_email: str = settings.DEFAULT_FROM_EMAIL
|
|
) -> int:
|
|
"""
|
|
Sends a single, template-based email to one user.
|
|
"""
|
|
recipient_list = [user.email]
|
|
|
|
# 1. Render content from template
|
|
html_content = render_to_string(template_name, context)
|
|
# You can optionally render a plain text version as well:
|
|
# text_content = strip_tags(html_content)
|
|
|
|
# 2. Call internal sender
|
|
return self._send_email_internal(
|
|
subject=subject,
|
|
body="", # Can be empty if html_content is provided
|
|
recipient_list=recipient_list,
|
|
from_email=from_email,
|
|
html_content=html_content
|
|
)
|
|
|
|
def send_bulk_email(
|
|
self,
|
|
recipient_emails: List[str],
|
|
subject: str,
|
|
template_name: str,
|
|
context: dict,
|
|
from_email: str = settings.DEFAULT_FROM_EMAIL
|
|
) -> int:
|
|
"""
|
|
Sends the same template-based email to a list of email addresses.
|
|
|
|
Note: Django's EmailMessage can handle multiple recipients in one
|
|
transaction, which is often more efficient than sending them one-by-one.
|
|
"""
|
|
|
|
# 1. Render content from template (once)
|
|
html_content = render_to_string(template_name, context)
|
|
|
|
# 2. Call internal sender with all recipients
|
|
# The result here is usually 1 if successful, as it uses a single
|
|
# EmailMessage call for all recipients.
|
|
sent_count = self._send_email_internal(
|
|
subject=subject,
|
|
body="",
|
|
recipient_list=recipient_emails,
|
|
from_email=from_email,
|
|
html_content=html_content
|
|
)
|
|
|
|
# Return the count of recipients if successful, or 0 if failure
|
|
return len(recipient_emails) if sent_count > 0 else 0
|