imip-agent

Annotated imiptools/mail.py

466:8d2dfe43b629
2015-03-31 Paul Boddie Fixed free/busy period conversion to retain the original period instance types.
paul@83 1
#!/usr/bin/env python
paul@83 2
paul@146 3
"""
paul@146 4
Mail preparation support.
paul@146 5
paul@146 6
Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
paul@146 7
paul@146 8
This program is free software; you can redistribute it and/or modify it under
paul@146 9
the terms of the GNU General Public License as published by the Free Software
paul@146 10
Foundation; either version 3 of the License, or (at your option) any later
paul@146 11
version.
paul@146 12
paul@146 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@146 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@146 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@146 16
details.
paul@146 17
paul@146 18
You should have received a copy of the GNU General Public License along with
paul@146 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@146 20
"""
paul@146 21
paul@128 22
from imiptools.config import MESSAGE_SENDER, OUTGOING_PREFIX
paul@83 23
from email.mime.message import MIMEMessage
paul@83 24
from email.mime.multipart import MIMEMultipart
paul@83 25
from email.mime.text import MIMEText
paul@83 26
from smtplib import LMTP, SMTP
paul@83 27
paul@83 28
MESSAGE_SUBJECT = "Calendar system message"
paul@83 29
paul@83 30
MESSAGE_TEXT = """\
paul@139 31
This is a message from the calendar system.
paul@83 32
"""
paul@83 33
paul@87 34
PREAMBLE_TEXT = """\
paul@87 35
This message contains several different parts, one of which will contain
paul@87 36
calendar information that will only be understood by a suitable program.
paul@87 37
"""
paul@87 38
paul@83 39
class Messenger:
paul@83 40
paul@83 41
    "Sending of outgoing messages."
paul@83 42
paul@87 43
    def __init__(self, sender=None, subject=None, body_text=None, preamble_text=None):
paul@83 44
        self.sender = sender or MESSAGE_SENDER
paul@83 45
        self.subject = subject or MESSAGE_SUBJECT
paul@83 46
        self.body_text = body_text or MESSAGE_TEXT
paul@87 47
        self.preamble_text = preamble_text or PREAMBLE_TEXT
paul@83 48
paul@128 49
    def sendmail(self, recipients, data, sender=None, outgoing_bcc=None, lmtp_socket=None):
paul@83 50
paul@83 51
        """
paul@83 52
        Send a mail to the given 'recipients' consisting of the given 'data',
paul@128 53
        using the given 'sender' identity if indicated, indicating an
paul@128 54
        'outgoing_bcc' identity if indicated, delivering to a local mail system
paul@128 55
        using LMTP if 'lmtp_socket' is provided.
paul@445 56
paul@445 57
        The 'outgoing_bcc' argument is required when sending on behalf of a user
paul@445 58
        from the calendar@domain address, since this will not be detected as a
paul@445 59
        valid participant and handled using the outgoing transport.
paul@83 60
        """
paul@83 61
paul@83 62
        if lmtp_socket:
paul@83 63
            smtp = LMTP(lmtp_socket)
paul@83 64
        else:
paul@83 65
            smtp = SMTP("localhost")
paul@83 66
paul@128 67
        if outgoing_bcc:
paul@128 68
            recipients = list(recipients) + ["%s+%s" % (OUTGOING_PREFIX, outgoing_bcc)]
paul@128 69
paul@86 70
        smtp.sendmail(sender or self.sender, recipients, data)
paul@83 71
        smtp.quit()
paul@83 72
paul@178 73
    def make_outgoing_message(self, parts, recipients, sender=None, outgoing_bcc=None):
paul@83 74
paul@86 75
        """
paul@86 76
        Make a message from the given 'parts' for the given 'recipients', using
paul@128 77
        the given 'sender' identity if indicated, indicating an 'outgoing_bcc'
paul@128 78
        identity if indicated.
paul@86 79
        """
paul@83 80
paul@178 81
        message = self._make_summary_for_parts(parts)
paul@83 82
paul@86 83
        message["From"] = sender or self.sender
paul@83 84
        for recipient in recipients:
paul@83 85
            message["To"] = recipient
paul@128 86
        if outgoing_bcc:
paul@128 87
            message["Bcc"] = "%s+%s" % (OUTGOING_PREFIX, outgoing_bcc)
paul@83 88
        message["Subject"] = self.subject
paul@83 89
paul@83 90
        return message
paul@83 91
paul@178 92
    def make_summary_message(self, msg, parts):
paul@178 93
paul@178 94
        """
paul@178 95
        Return a simple summary using details from 'msg' and the given 'parts'.
paul@178 96
        """
paul@178 97
paul@178 98
        message = self._make_summary_for_parts(parts)
paul@178 99
        self._copy_headers(message, msg)
paul@178 100
        return message
paul@178 101
paul@83 102
    def wrap_message(self, msg, parts):
paul@83 103
paul@83 104
        "Wrap 'msg' and provide the given 'parts' as the primary content."
paul@83 105
paul@178 106
        message = self._make_container_for_parts(parts)
paul@178 107
        payload = message.get_payload()
paul@178 108
        payload.append(MIMEMessage(msg))
paul@178 109
        self._copy_headers(message, msg)
paul@178 110
        return message
paul@178 111
paul@178 112
    def _make_summary_for_parts(self, parts):
paul@178 113
paul@178 114
        "Return a simple summary for the given 'parts'."
paul@178 115
paul@178 116
        if len(parts) == 1:
paul@178 117
            return parts[0]
paul@178 118
        else:
paul@178 119
            return self._make_container_for_parts(parts)
paul@178 120
paul@178 121
    def _make_container_for_parts(self, parts):
paul@178 122
paul@178 123
        "Return a container for the given 'parts'."
paul@178 124
paul@83 125
        message = MIMEMultipart("mixed", _subparts=parts)
paul@87 126
        message.preamble = self.preamble_text
paul@178 127
        return message
paul@83 128
paul@178 129
    def _copy_headers(self, message, msg):
paul@83 130
        message["From"] = msg["From"]
paul@83 131
        message["To"] = msg["To"]
paul@83 132
        message["Subject"] = msg["Subject"]
paul@83 133
paul@83 134
# vim: tabstop=4 expandtab shiftwidth=4