view rhodecode/lib/rcmail/message.py @ 1818:cf51bbfb120e beta

auto white-space removal
author Marcin Kuzminski <marcin@python-works.com>
date Thu, 29 Dec 2011 07:35:51 +0200
parents 7ff304d3028f
children 349a0ca30a75
line wrap: on
line source

from rhodecode.lib.rcmail.response import MailResponse

from rhodecode.lib.rcmail.exceptions import BadHeaders
from rhodecode.lib.rcmail.exceptions import InvalidMessage

class Attachment(object):
    """
    Encapsulates file attachment information.

    :param filename: filename of attachment
    :param content_type: file mimetype
    :param data: the raw file data, either as string or file obj
    :param disposition: content-disposition (if any)
    """

    def __init__(self,
                 filename=None,
                 content_type=None,
                 data=None,
                 disposition=None):

        self.filename = filename
        self.content_type = content_type
        self.disposition = disposition or 'attachment'
        self._data = data

    @property
    def data(self):
        if isinstance(self._data, basestring):
            return self._data
        self._data = self._data.read()
        return self._data


class Message(object):
    """
    Encapsulates an email message.

    :param subject: email subject header
    :param recipients: list of email addresses
    :param body: plain text message
    :param html: HTML message
    :param sender: email sender address
    :param cc: CC list
    :param bcc: BCC list
    :param extra_headers: dict of extra email headers
    :param attachments: list of Attachment instances
    """

    def __init__(self,
                 subject=None,
                 recipients=None,
                 body=None,
                 html=None,
                 sender=None,
                 cc=None,
                 bcc=None,
                 extra_headers=None,
                 attachments=None):


        self.subject = subject or ''
        self.sender = sender
        self.body = body
        self.html = html

        self.recipients = recipients or []
        self.attachments = attachments or []
        self.cc = cc or []
        self.bcc = bcc or []
        self.extra_headers = extra_headers or {}

    @property
    def send_to(self):
        return set(self.recipients) | set(self.bcc or ()) | set(self.cc or ())

    def to_message(self):
        """
        Returns raw email.Message instance.Validates message first.
        """

        self.validate()

        return self.get_response().to_message()

    def get_response(self):
        """
        Creates a Lamson MailResponse instance
        """

        response = MailResponse(Subject=self.subject,
                                To=self.recipients,
                                From=self.sender,
                                Body=self.body,
                                Html=self.html)

        if self.bcc:
            response.base['Bcc'] = self.bcc

        if self.cc:
            response.base['Cc'] = self.cc

        for attachment in self.attachments:

            response.attach(attachment.filename,
                            attachment.content_type,
                            attachment.data,
                            attachment.disposition)

        response.update(self.extra_headers)

        return response

    def is_bad_headers(self):
        """
        Checks for bad headers i.e. newlines in subject, sender or recipients.
        """

        headers = [self.subject, self.sender]
        headers += list(self.send_to)
        headers += self.extra_headers.values()

        for val in headers:
            for c in '\r\n':
                if c in val:
                    return True
        return False

    def validate(self):
        """
        Checks if message is valid and raises appropriate exception.
        """

        if not self.recipients:
            raise InvalidMessage, "No recipients have been added"

        if not self.body and not self.html:
            raise InvalidMessage, "No body has been set"

        if not self.sender:
            raise InvalidMessage, "No sender address has been set"

        if self.is_bad_headers():
            raise BadHeaders

    def add_recipient(self, recipient):
        """
        Adds another recipient to the message.

        :param recipient: email address of recipient.
        """

        self.recipients.append(recipient)

    def add_cc(self, recipient):
        """
        Adds an email address to the CC list.

        :param recipient: email address of recipient.
        """

        self.cc.append(recipient)

    def add_bcc(self, recipient):
        """
        Adds an email address to the BCC list.

        :param recipient: email address of recipient.
        """

        self.bcc.append(recipient)

    def attach(self, attachment):
        """
        Adds an attachment to the message.

        :param attachment: an **Attachment** instance.
        """

        self.attachments.append(attachment)