dbmail framework for sending and receiving emails in the ESP Website
The ESP Website uses the dbmail system to manage both outgoing and incoming email. This system stores email data in the database and processes it through cron jobs, providing reliability and audit trails for all communications.
Emails originate from the communications panel where admins write email templates and select recipients:
from esp.dbmail.models import MessageRequestfrom esp.users.models import ESPUser, PersistentQueryFilter# Create a query filter for recipientsrecipients_filter = PersistentQueryFilter.create_from_Q( ESPUser, Q(studentinfo__program=program))# Create the message requestmsg_request = MessageRequest.objects.create( subject="Welcome to {{ program.niceName }}!", msgtext="""Dear {{ user.first_name }}, Thank you for registering for {{ program.niceName }}. Your classes start on {{ program.startdate }}. Best regards, The {{ program.director_email }} Team """, sender="Splash Directors <[email protected]>", recipients=recipients_filter, creator=request.user, sendto_fn_name=MessageRequest.SEND_TO_SELF)
The esp/dbmail_cron.py script runs every 15 minutes and:
Processes unprocessed MessageRequests: For each recipient, creates a TextOfEmail with variables substituted
Sends unsent TextOfEmail objects: Delivers emails via SMTP and marks them as sent
# In dbmail_cron.py (simplified)for msg_request in MessageRequest.objects.filter(processed=False): msg_request.process()for email in TextOfEmail.objects.filter(sent__isnull=True): email.send()
Control who receives the email for each recipient user:
# Send to the user only (default)MESSAGE_REQUEST.SEND_TO_SELF # ''# Send to user's guardianMESSAGE_REQUEST.SEND_TO_GUARDIAN# Send to emergency contactMESSAGE_REQUEST.SEND_TO_EMERGENCY# Send to multiple recipientsMESSAGE_REQUEST.SEND_TO_SELF_AND_GUARDIANMESSAGE_REQUEST.SEND_TO_SELF_AND_EMERGENCYMESSAGE_REQUEST.SEND_TO_GUARDIAN_AND_EMERGENCYMESSAGE_REQUEST.SEND_TO_SELF_AND_GUARDIAN_AND_EMERGENCY
Example sending to students and guardians:
msg_request = MessageRequest.objects.create( subject="Important Program Update", msgtext="...", recipients=student_filter, sendto_fn_name=MessageRequest.SEND_TO_SELF_AND_GUARDIAN, creator=admin_user)
# The send() method handles the actual SMTP transmissionemail = TextOfEmail.objects.get(id=some_id)result = email.send()if result is None: print("Email sent successfully")else: print(f"Error: {result}")
When sending to users, unsubscribe headers are automatically added:
# Automatically added for emails with user parameterextra_headers['List-Unsubscribe-Post'] = "List-Unsubscribe=One-Click"extra_headers['List-Unsubscribe'] = '<{unsubscribe_url}>'
Incoming emails are routed based on regex patterns:
from esp.dbmail.models import EmailList# Route class emails to students and teachersEmailList.objects.create( regex=r'^(.+)-students@', handler='class_mailman', seq=10, description='Class email lists')
from esp.dbmail.models import send_mailsend_mail( subject="Test Email", message="This is a test message.", from_email="[email protected]", recipient_list=["[email protected]"], fail_silently=False, extra_headers={'Reply-To': '[email protected]'}, user=user_instance # For unsubscribe headers)
The from_email must match your DMARC domains (typically @yoursite.org or @learningu.org) or the email may be rejected by recipients.