Source code for uw.local.outgoing.bin.loopback2

"""Loopback monitor implementation.

This module implements the loopback handler.  Email received by the loopback
address is processed by this module, which notes the corresponding email
request within the system as having been received on loopback.  This provides
verification that the email has in fact been handled by the email system.  Of
course, nothing can guarantee the message isn't lost elsewhere, but it at least
guarantees the message made it as far as the first mail server.
"""

import sys
import re
import email
from email.utils import *

from uw.sql.wrap import open_psycopg2_db_service_cursor

loopback_address = ('Odyssey Mail Loopback', 'outgoing-loopback@odyssey.uwaterloo.ca')
loopback_header = "Message-Id"

[docs]def set_message_loopback (msg, cursor, msg_id): """Apply the message loopback header to a message. :param email.message.Message msg: the received email message. :param cursor: DB connection cursor. :param int msg_id: the sequential database message ID. Sets the Message-Id of the message to the one stored in the database for the specified message ID. If there is already a Message-Id it is replaced. This is used by the mail sending process to set the Message-Id on outgoing messages. """ del msg[loopback_header] msg[loopback_header] = get_message_id (cursor, msg_id)
loopback_regex = re.compile (r"\.(\d+)@")
[docs]def get_message_loopback (msg): """Read the loopback header information from a message. :param email.message.Message msg: the received email message. This reads the loopback header and extracts the sequential database message ID, or None if the header is not in the required format. """ match = loopback_regex.search (msg[loopback_header]) if match is None: return None return int (match.group (1))
[docs]def get_message_id (cursor, msg_id): """Get the loopback header for a designated message. :param cursor: DB connection cursor. :param int msg_id: the sequential database message ID. This just reads the SMTP Message ID for the specified message from the database. """ return cursor.execute_optional_value ("SELECT smtp_message_id FROM mail_message WHERE msg_id=%(msg_id)s", msg_id=msg_id)
[docs]def assign_message_id (cursor, msg_id): """Assign the loopback header value for a designated message. :param cursor: DB connection cursor. :param int msg_id: the sequential database message ID. If the message already has its loopback header value assigned, no change is made. """ message_id = make_msgid (str (msg_id)) cursor.execute_none ("UPDATE mail_message SET (smtp_message_id) = (%(smtp_message_id)s) WHERE msg_id=%(msg_id)s AND smtp_message_id IS NULL", smtp_message_id=message_id, msg_id=msg_id)
[docs]def record_message_loopback (cursor, msg_id): """Record in the database the receipt of a message loopback. :param cursor: DB connection cursor. :param int msg_id: the sequential database message ID. """ cursor.execute_none ("INSERT INTO mail_message_loopback (msg_id) VALUES (%(msg_id)s)", msg_id=msg_id)
[docs]def main (): """Program entry point for receiving messages on loopback. Opens a database connection, parses the incoming message to object the Message ID, then records receipt of the message in the database. """ cursor = open_psycopg2_db_service_cursor () msg = email.message_from_file (sys.stdin) msg_id = get_message_loopback (msg) if get_message_id (cursor, msg_id) == msg[loopback_header]: record_message_loopback (cursor, msg_id) cursor.connection.commit () else: print("Unexpected Message-Id: %s" % msg[loopback_header]) print(str (msg))