Example #1
0
def create_mail(subject,
                message,
                from_email,
                recipient,
                message_html=None,
                attachments=None,
                rfc2822_headers=None):

    headers = {'Message-ID': make_msgid()}

    if rfc2822_headers:
        headers.update(rfc2822_headers)

    if message is None:  # make text version out of html if text version is missing
        message = html2text(message_html)

    if message_html:
        msg = EmailMultiAlternatives(subject,
                                     message,
                                     from_email, [recipient],
                                     headers=headers)
        msg.attach_alternative(message_html, "text/html")
    else:
        msg = EmailMessage(subject,
                           message,
                           from_email, [recipient],
                           headers=headers)

    if attachments:
        for filename, content, mimetype in attachments:
            msg.attach(filename, content, mimetype)

    return msg
Example #2
0
    def form_valid(self, form, **kwargs):
        email = form.cleaned_data['email']
        name = form.cleaned_data['name']

        from_email = '"{}" <{}>'.format(name, email)
        reply_to = from_email
        to_email = [settings.HELPDESK_ADDRESS]

        headers = {'Reply-To': reply_to,
                   'Message-Id': make_msgid()}

        # do spam checks, assignment email, cc_asker
        if form.cleaned_data['author']:
            return self.handle_spam(form, from_email, headers)
        if settings.ENABLE_HELPDESKQ:
            self.handle_assignment(form,
                                   headers=headers,
                                   message_id=headers.get('Message-Id', None))
        if settings.HELPDESK_CC_ASKER:
            self.handle_confirmation(form, from_email)

        return super(HelpdeskEmailerView, self).form_valid(
            form,
            from_email=from_email,
            to_email=to_email,
            headers=headers,
            **kwargs)
Example #3
0
def emailimage_media(context, image):
    if not context.get('render_mail', False):
        return default_storage.url(image)

    if 'attachments' not in context:
        context['attachments'] = {}

    key = "media:" + image

    if key not in context['attachments']:
        path = default_storage.path(image)
        if path is not None:
            with open(path, 'rb') as fh:
                image_data = fh.read()
        else:
            return ""  # not found!

        image_cid = make_msgid('img')

        mime = MIMEImage(image_data)
        mime.add_header('Content-ID', image_cid)

        context['attachments'][key] = (mime, image_cid[1:-1])

    return "cid:{}".format(context['attachments'][key][1])
Example #4
0
File: mail.py Project: emulbreh/ecs
def deliver(subject, message, from_email, recipient_list, message_html=None, attachments= None, callback=None, **kwargs):
    """
    send email to recipient list (filter them through settings.EMAIL_WHITELIST if exists), 
    puts messages to send into celery queue
    returns a list of (msgid, rawmessage) for each messages to be sent
    if callback is set to a celery task:
       it will be called on every single recipient delivery with callback(msgid, status)
    """
    # make a list if only one recipient (and therefore string) is there
    if isinstance(recipient_list, basestring):
        recipient_list = [recipient_list]
 
    # filter out recipients which are not in the whitelist
    mylist = set(recipient_list)
    bad = None
    if hasattr(settings, "EMAIL_WHITELIST") and settings.EMAIL_WHITELIST:
        bad = set([x for x in recipient_list if x not in settings.EMAIL_WHITELIST])
    if bad:
        logger = logging.getLogger()
        logger.warning('BAD EMAILS: %s are bad out of %s' % (str(bad), str(mylist)))
        recipient_list = list(mylist - bad)

    sentids = []
    for recipient in recipient_list:
        msgid = make_msgid()
        msg = create_mail(subject, message, from_email, recipient, message_html, attachments, msgid)
        
        queued_mail_send.apply_async(args=[msgid, msg, from_email, recipient, callback], countdown=3)
        #queued_mail_send(msgid, msg, from_email, recipient, callback)
        sentids += [[msgid, msg.message()]]
    return sentids
Example #5
0
    def test_embedded_images(self):
        image_data = self.sample_image_content()  # Read from a png file
        image_cid = make_msgid(
            "img")  # Content ID per RFC 2045 section 7 (with <...>)
        image_cid_no_brackets = image_cid[
            1:-1]  # Without <...>, for use as the <img> tag src

        text_content = 'This has an inline image.'
        html_content = '<p>This has an <img src="cid:%s" alt="inline" /> image.</p>' % image_cid_no_brackets
        email = mail.EmailMultiAlternatives('Subject', text_content,
                                            '*****@*****.**',
                                            ['*****@*****.**'])
        email.attach_alternative(html_content, "text/html")

        image = MIMEImage(image_data)
        image.add_header('Content-ID', image_cid)
        email.attach(image)

        email.send()
        data = self.get_api_call_data()
        self.assertEqual(data['message']['text'], text_content)
        self.assertEqual(data['message']['html'], html_content)
        self.assertEqual(len(data['message']['images']), 1)
        self.assertEqual(data['message']['images'][0]["type"], "image/png")
        self.assertEqual(data['message']['images'][0]["name"], image_cid)
        self.assertEqual(decode_att(data['message']['images'][0]["content"]),
                         image_data)
        # Make sure neither the html nor the inline image is treated as an attachment:
        self.assertFalse('attachments' in data['message'])
Example #6
0
def emailimage_static(context, image):
    if not context.get('render_mail', False):
        t = template.Template(r"{% load staticfiles %}{% static '" + image +
                              "' %}")
        return t.render(context)

    if 'attachments' not in context:
        context['attachments'] = {}

    key = "static:" + image

    if key not in context['attachments']:
        path = finders.find(image)
        if path is not None:
            with open(path, 'rb') as fh:
                image_data = fh.read()
        else:
            return ""  # not found!

        image_cid = make_msgid('img')

        mime = MIMEImage(image_data)
        mime.add_header('Content-ID', image_cid)

        context['attachments'][key] = (mime, image_cid[1:-1])

    return "cid:{}".format(context['attachments'][key][1])
Example #7
0
def attach_inline_image(message, content, filename=None, subtype=None, idstring="img", domain=None):
    """Add inline image to an EmailMessage, and return its content id"""
    content_id = make_msgid(idstring, domain)  # Content ID per RFC 2045 section 7 (with <...>)
    image = MIMEImage(content, subtype)
    image.add_header('Content-Disposition', 'inline', filename=filename)
    image.add_header('Content-ID', content_id)
    message.attach(image)
    return unquote(content_id)  # Without <...>, for use as the <img> tag src
    def make_message_id(self):
        """Returns a Message-ID that could be used for this payload

        Tries to use the from_email's domain as the Message-ID's domain
        """
        try:
            _, domain = self.data["from"].split("@")
        except (AttributeError, KeyError, TypeError, ValueError):
            domain = None
        return make_msgid(domain=domain)
Example #9
0
    def make_message_id(self):
        """Returns a Message-ID that could be used for this payload

        Tries to use the from_email's domain as the Message-ID's domain
        """
        try:
            _, domain = self.data["from"]["email"].split("@")
        except (AttributeError, KeyError, TypeError, ValueError):
            domain = None
        return make_msgid(domain=domain)
Example #10
0
def attach_inline_image(message, content, filename=None, subtype=None, idstring="img", domain=None):
    """Add inline image to an EmailMessage, and return its content id"""
    if domain is None:
        # Avoid defaulting to hostname that might end in '.com', because some ESPs
        # use Content-ID as filename, and Gmail blocks filenames ending in '.com'.
        domain = 'inline'  # valid domain for a msgid; will never be a real TLD
    content_id = make_msgid(idstring, domain)  # Content ID per RFC 2045 section 7 (with <...>)
    image = MIMEImage(content, subtype)
    image.add_header('Content-Disposition', 'inline', filename=filename)
    image.add_header('Content-ID', content_id)
    message.attach(image)
    return unquote(content_id)  # Without <...>, for use as the <img> tag src
Example #11
0
def _embed_images(template, images, test=False):
    for image in images:
        src_attr = 'src="cid:{}"'.format(image.placeholder_name)
        if test:
            replace_src = 'src="{}"'.format(image.image.url)
        else:
            if not len(image.content_id):
                image.content_id = make_msgid(image.placeholder_name)
                image.save()
            replace_src = 'src="cid:{}"'.format(image.content_id[1:-1])
        template = template.replace(src_attr, replace_src)
    return template
Example #12
0
    def receive(self, subject, message, from_email, recipient_list, message_html=None, attachments=None, connecting_host="localhost"):
        ''' Fakes an incoming message trough ecsmail server '''
        if isinstance(recipient_list, basestring):
            recipient_list = [recipient_list]

        sentids = []
        for recipient in recipient_list:
            msgid = make_msgid()
            msg = create_mail(subject, message, from_email, recipient, message_html, attachments, msgid)
            self.logger.debug("Receiving Mail from %s to %s, message= %s" % (from_email, recipient, str(msg.message())))
            routing.Router.deliver(MailRequest(connecting_host, from_email, recipient, str(msg.message())))
            sentids += [[msgid, msg.message()]]
            
        return sentids
Example #13
0
    def send_out_email(self):
        lv = self.latest_version()
        msg_id = getattr(self, 'message_id', None)
        if not msg_id:
            msg_id = make_msgid()
            self.message_id = msg_id
            self.save()
            print "New msgid '%s' added to %s." % (msg_id, self)

        parent = lv.parent
        parent_msg_id = None
        if parent:
            parent_msg_id = getattr(parent, 'message_id', None)
        author_full_name = lv.author.get_full_name()
        author_email = lv.author.email
        author = "%s <%s>" % (author_full_name, author_email)

        heap = self.get_heap()
        recipients = [user['email'] for user in heap.user_fields.values()]

        print "Emails will be sent out to:"
        for to in recipients:
            print to

        msg_subject = self.get_conversation().subject

        # tags =

        body = self.latest_version().text

        if hasattr(settings, 'HEAP_EMAIL_DOMAIN'):
            reply_address = heap.short_name + '@' + settings.HEAP_EMAIL_DOMAIN
        else:
            reply_address = settings.EMAIL_HOST_USER

        extra_headers = {'Reply-To': reply_address, 'From': author}
        if msg_id:
            extra_headers['Message-ID'] = msg_id
        if parent_msg_id:
            extra_headers['In-Reply-To'] = parent_msg_id

        # TODO use a meaningful sender address!
        email = EmailMessage(msg_subject,
                             body,
                             settings.EMAIL_HOST_USER,
                             recipients,
                             None,
                             headers=extra_headers)
        email.send()
Example #14
0
    def test_answer_timeout_recipient(self):
        old_timestamp = self.last_message.timestamp
        recipient = self.last_message.return_address
        self.last_message.timestamp = timezone.now() - timedelta(
            days=EcsMailReceiver.ANSWER_TIMEOUT+ 1)
        self.last_message.save()

        msgid = make_msgid()
        msg = MIMEText('This is a test reply.')
        msg['From'] = 'Bob <*****@*****.**>'
        msg['To'] = 'Alice <{}>'.format(recipient)
        msg['Message-ID'] = msgid

        self.assertEqual(EcsMailReceiver.ANSWER_TIMEOUT, 365)
        code, description = self.process_message([recipient], msg)
        self.assertEqual(code, 553)
        self.assertEqual(description, 'Invalid recipient <{}>'.format(recipient))
Example #15
0
    def send_out_email(self):
        lv = self.latest_version()
        msg_id = getattr(self, 'message_id', None)
        if not msg_id:
            msg_id = make_msgid()
            self.message_id = msg_id
            self.save()
            print "New msgid '%s' added to %s." % (msg_id, self)

        parent = lv.parent
        parent_msg_id = None
        if parent:
            parent_msg_id = getattr(parent, 'message_id', None)
        author_full_name = lv.author.get_full_name()
        author_email = lv.author.email
        author = "%s <%s>" % (author_full_name, author_email)

        heap = self.get_heap()
        recipients = [user['email'] for user in heap.user_fields.values()]

        print "Emails will be sent out to:"
        for to in recipients:
           print to

        msg_subject = self.get_conversation().subject

        # tags = 

        body = self.latest_version().text

        if hasattr(settings, 'HEAP_EMAIL_DOMAIN'):
            reply_address = heap.short_name + '@' + settings.HEAP_EMAIL_DOMAIN
        else:
            reply_address = settings.EMAIL_HOST_USER

        extra_headers = {'Reply-To': reply_address, 'From': author}
        if msg_id:
            extra_headers['Message-ID'] = msg_id
        if parent_msg_id:
            extra_headers['In-Reply-To'] = parent_msg_id

        # TODO use a meaningful sender address!
        email = EmailMessage(msg_subject, body, settings.EMAIL_HOST_USER,
                    recipients, None,
                    headers=extra_headers)
        email.send()
Example #16
0
    def form_valid(self, form, **kwargs):
        email = form.cleaned_data['email']
        name = form.cleaned_data['name']

        from_email = '"{}" <{}>'.format(name, email)
        reply_to = from_email

        headers = {'Reply-To': reply_to,
                   'Message-Id': make_msgid()}

        if self.check_spam and form.cleaned_data['author']:
            return self.handle_spam(form, from_email, headers)

        return super(CompanyEmailerView, self).form_valid(
            form,
            to_email=[settings.INDREL_ADDRESS],
            **kwargs)
Example #17
0
    def test_plain(self):
        recipient = self.last_message.return_address
        msgid = make_msgid()
        msg = MIMEText('This is a test reply.')
        msg['From'] = 'Bob <*****@*****.**>'
        msg['To'] = 'Alice <{}>'.format(recipient)
        msg['Message-ID'] = msgid

        code, description = self.process_message([recipient], msg)
        self.assertEqual(code, 250)
        self.assertEqual(description, 'Ok')
        self.assertEqual(self.thread.messages.count(), 2)

        reply = self.thread.messages.get(rawmsg_msgid=msgid)
        self.assertEqual(reply.text, 'This is a test reply.')
        self.assertEqual(reply.sender, self.bob)
        self.assertEqual(reply.receiver, self.alice)
Example #18
0
    def message(self):
        """
        Returns a email.message.Message object. The object is based on original_message if
        original_message is not None.
        """

        if self.original_message is None:
            result_message = super().message()
        else:

            msg = self._create_message(self.original_message)

            # Remove managed header from message
            for key in self.manage_headers:
                if key in msg:
                    del msg[key]

            msg['To'] = ', '.join(self.to) or self.extra_headers.get('to', '')
            msg['Cc'] = ', '.join(self.cc) or self.extra_headers.get('cc', '')
            msg['Bcc'] = ', '.join(self.bcc) or self.extra_headers.get('bcc', '')
            msg['From'] = self.from_email or self.extra_headers.get('from', '')
            msg['Reply-To'] = ', '.join(self.reply_to) or self.extra_headers.get('reply-to', '')
            msg['Subject'] = self.subject or self.extra_headers.get('subject', '*** No Subject ***')

            # Check for missing headers
            header_names = [key.lower() for key in self.extra_headers]
            if 'date' not in header_names:
                msg['Date'] = formatdate()
            if 'message-id' not in header_names:
                msg['Message-ID'] = make_msgid(domain=DNS_NAME)
            # Set extra headers
            for name, value in self.extra_headers.items():
                if name.lower() in self.manage_headers:
                    continue
                if name.lower() in msg:
                    del msg[name]
                msg[name] = value

            if self.body is not None:
                log.warning('The message method constructed a email.message.Message based on '
                            'original_message. The content of body is lost!')

            result_message = msg

        return result_message
Example #19
0
def inline_images(message, html):
    """Given HTML with inline data images, convert these to attachments,
    and add HTML as an alternative
    """
    images = re.findall(r'<img.*?src="data:image/png;base64,.*?">', html)
    for i, image_tag in enumerate(images):
        filename = "img{}.png".format(i)
        data = re.findall(r'<img.*?src="data:image/png;base64,(.*?)">',
                          image_tag)[0]
        content_id = make_msgid(
            "img")  # Content ID per RFC 2045 section 7 (with <...>)
        image = MIMEImage(data, "png", _encoder=lambda x: x)
        image.add_header("Content-Disposition", "inline", filename=filename)
        image.add_header("Content-ID", content_id)
        image.add_header("Content-Transfer-Encoding", "base64")
        message.attach(image)
        html = html.replace(image_tag,
                            '<img src="cid:{}">'.format(unquote(content_id)))
    message.attach_alternative(html, "text/html")
    return message
Example #20
0
File: mail.py Project: emulbreh/ecs
def create_mail(subject, message, from_email, recipient, message_html=None, attachments= None, msgid=None, **kwargs):
    '''
    '''
    if msgid is None:
        msgid = make_msgid()
    headers = {'Message-ID': msgid}
    
    if message is None: # make text version out of html if text version is missing
        message = whitewash(message_html)
    
    if message and message_html:
        msg = EmailMultiAlternatives(subject, message, from_email, [recipient], headers= headers)
        msg.attach_alternative(message_html, "text/html")
    else:
        msg = EmailMessage(subject, message, from_email, [recipient], headers= headers)
      
    if attachments:
        for attachment in attachments:
            filename = content = mimetype = encoding = None
            
            if isinstance(attachment, tuple) or isinstance(attachment, list):
                filename, content = attachment[0:2]
                if len(attachment) == 3:
                    mimetype = attachment[2]
                else:
                    mimetype, encoding = mimetypes.guess_type(filename)
            elif isinstance(attachment, basestring):
                filename = attachment
                if not os.path.exists(filename):
                    raise IOError("attachment file not found %s" % filename)
                mimetype, encoding = mimetypes.guess_type(filename)    
                content = open(filename, "rb").read()
            else:
                raise TypeError('dont know how to handle attachment from type %s' % (str(type(attachment))))

            if not mimetype:
                raise TypeError("No content type given, and couldn't guess from the filename: %s" % filename)
                
            msg.attach(filename, content, mimetype)
            
    return msg
Example #21
0
File: mail.py Project: subc/anchovy
    def message(self):
        if len(self.to) == 1:
            carrier = get_carrier_by_email_address(self.to[0]) or 'N'
        else:
            # TODO
            carrier = 'N'

        msg = make_message(carrier,
                           smart_unicode(self.subject),
                           smart_unicode(self.body),
                           errors=self.errors)

        msg['From'] = self.from_email
        msg['To'] = ', '.join(self.to)
        msg['Date'] = formatdate()
        msg['Message-ID'] = make_msgid()
        if self.bcc:
            msg['Bcc'] = ', '.join(self.bcc)
        for name, value in self.extra_headers.items():
            msg[name] = value
        return msg
Example #22
0
    def send_mail(self):
        """Send event request email generated using form data."""
        template = get_template('email/event.txt')
        context = self.cleaned_data
        email = template.render(context)
        subject, body = email.split("\n", 1)
        from_email = settings.EVENT_EMAIL
        to_email = self.cleaned_data['email']

        message_id = make_msgid()
        email = EmailMessage(subject, body, from_email, [to_email, from_email],
                    headers={'Message-ID': message_id}
        )
        email.send()


        event_url = self.tracker_event(context)
        tracker_email = EmailMessage(subject, event_url, from_email, [from_email],
            headers={'In-Reply-To': message_id})
        tracker_email.send()
        return self.cleaned_data
Example #23
0
    def message(self):
        if len(self.to) == 1:
            carrier = get_carrier_by_email_address(self.to[0]) or 'N'
        else:
            # TODO
            carrier = 'N'

        msg = make_message(carrier,
                           smart_unicode(self.subject),
                           smart_unicode(self.body),
                           errors=self.errors)

        msg['From'] = self.from_email
        msg['To'] = ', '.join(self.to)
        msg['Date'] = formatdate()
        msg['Message-ID'] = make_msgid()
        if self.bcc:
            msg['Bcc'] = ', '.join(self.bcc)
        for name, value in self.extra_headers.items():
            msg[name] = value
        return msg
Example #24
0
    def send_mail(self):
        """Send event request email generated using form data."""
        template = get_template('email/event.txt')
        context = self.cleaned_data
        email = template.render(context)
        subject, body = email.split("\n", 1)
        from_email = settings.EVENT_EMAIL
        to_email = self.cleaned_data['email']

        message_id = make_msgid()
        email = EmailMessage(subject, body, from_email, [to_email, from_email],
                    headers={'Message-ID': message_id}
        )
        email.send()


        event_url = self.tracker_event(context)
        tracker_email = EmailMessage(subject, event_url, from_email, [from_email],
            headers={'In-Reply-To': message_id})
        tracker_email.send()
        return self.cleaned_data
Example #25
0
    def test_mixed(self):
        recipient = self.last_message.return_address
        msgid = make_msgid()
        msg = MIMEMultipart('alternative')
        msg.attach(MIMEText('<html><body><p>HTML</p></body></html>', 'html'))
        msg.attach(MIMEText('PLAIN', 'plain'))
        msg['From'] = 'Bob <*****@*****.**>'
        msg['To'] = 'Alice <{}>'.format(recipient)
        msg['Message-ID'] = msgid

        code, description = self.process_message([recipient], msg)
        self.assertEqual(code, 250)
        self.assertEqual(description, 'Ok')
        self.assertEqual(self.thread.messages.count(), 2)

        reply = self.thread.messages.get(rawmsg_msgid=msgid)

        # When both HTML and plain text is available, the latter takes
        # precedence.
        self.assertEqual(reply.text, 'PLAIN')

        self.assertEqual(reply.sender, self.bob)
        self.assertEqual(reply.receiver, self.alice)
Example #26
0
    def test_embedded_images(self):
        image_data = self.sample_image_content()  # Read from a png file
        image_cid = make_msgid("img")  # Content ID per RFC 2045 section 7 (with <...>)
        image_cid_no_brackets = image_cid[1:-1]  # Without <...>, for use as the <img> tag src

        text_content = 'This has an inline image.'
        html_content = '<p>This has an <img src="cid:%s" alt="inline" /> image.</p>' % image_cid_no_brackets
        email = mail.EmailMultiAlternatives('Subject', text_content, '*****@*****.**', ['*****@*****.**'])
        email.attach_alternative(html_content, "text/html")

        image = MIMEImage(image_data)
        image.add_header('Content-ID', image_cid)
        email.attach(image)

        email.send()
        data = self.get_api_call_data()
        self.assertEqual(data['message']['text'], text_content)
        self.assertEqual(data['message']['html'], html_content)
        self.assertEqual(len(data['message']['images']), 1)
        self.assertEqual(data['message']['images'][0]["type"], "image/png")
        self.assertEqual(data['message']['images'][0]["name"], image_cid)
        self.assertEqual(decode_att(data['message']['images'][0]["content"]), image_data)
        # Make sure neither the html nor the inline image is treated as an attachment:
        self.assertFalse('attachments' in data['message'])
Example #27
0
 def generate_cid(self):
     self._content_id = make_msgid('img', self.domain)
Example #28
0
def send_mass_mail_recorded(datatuple, mailbox, related_object=None, bcc=None,
                            fail_silently=False, auth_user=None, auth_password=None, connection=None):
    """
    Shadows Django's send mass mail, but records each outgoing message to the
    specified mailbox.

    Also added optional bcc argument.
    """
    connection = connection or get_connection(
        username=auth_user, password=auth_password, fail_silently=fail_silently
    )

    messages = [EmailMessage(subject, message, sender, recipient, bcc, headers={'Message-ID': make_msgid()})
                for subject, message, sender, recipient in datatuple]

    record_messages(mailbox, messages, related_object)

    return connection.send_messages(messages)
Example #29
0
def send_mass_html_mail_recorded(datatuple, mailbox, related_object=None, bcc=None,
                                 fail_silently=False, user=None, password=None, connection=None):
    """
    Like above, but lets you send HTML emails.
    """
    connection = connection or get_connection(
        username=user, password=password, fail_silently=fail_silently
    )

    messages = []
    for subject, text, html, from_email, recipient in datatuple:
        message = EmailMultiAlternatives(subject, text, from_email, recipient, bcc, headers={'Message-ID': make_msgid()})
        message.attach_alternative(html, 'text/html')
        messages.append(message)

    record_messages(mailbox, messages)

    return connection.send_messages(messages)
    def message(self):
        """
        Returns the final message to be sent, including all headers etc. Content and attachments are encrypted using
        GPG in PGP/MIME format (RFC 3156).
        """

        def build_plain_message():
            msg = SafeMIMEText(self.body, self.content_subtype, encoding)
            msg = self._create_message(msg)
            return msg

        def build_version_attachment():
            version_attachment = SafeMIMEText('Version: 1\n', self.content_subtype, encoding)
            del version_attachment['Content-Type']
            version_attachment.add_header('Content-Type', 'application/pgp-encrypted')
            version_attachment.add_header('Content-Description', 'PGP/MIME Versions Identification')
            return version_attachment

        def build_gpg_attachment():
            gpg_attachment = SafeMIMEText(encrypted_msg, self.content_subtype, encoding)
            del gpg_attachment['Content-Type']
            gpg_attachment.add_header('Content-Type', 'application/octet-stream', name=self.gpg_attachment_filename)
            gpg_attachment.add_header('Content-Disposition', 'inline', filename=self.gpg_attachment_filename)
            gpg_attachment.add_header('Content-Description', 'OpenPGP encrypted message')
            return gpg_attachment

        encoding = self.encoding or settings.DEFAULT_CHARSET

        # build message including attachments as it would also be built without GPG
        msg = build_plain_message()

        # encrypt whole message including attachments
        encrypted_msg = self._encrypt(str(msg))

        # build new message object wrapping the encrypted message
        msg = SafeMIMEMultipart(_subtype=self.encrypted_subtype,
                                encoding=encoding,
                                protocol='application/pgp-encrypted')

        version_attachment = build_version_attachment()
        gpg_attachment = build_gpg_attachment()
        msg.attach(version_attachment)
        msg.attach(gpg_attachment)

        self.extra_headers['Content-Transfer-Encoding'] = '7bit'

        # add headers
        # everything below this line has not been modified when overriding message()
        ############################################################################

        msg['Subject'] = self.subject
        msg['From'] = self.extra_headers.get('From', self.from_email)
        msg['To'] = self.extra_headers.get('To', ', '.join(map(force_text, self.to)))
        if self.cc:
            msg['Cc'] = ', '.join(map(force_text, self.cc))
        if self.reply_to:
            msg['Reply-To'] = self.extra_headers.get('Reply-To', ', '.join(map(force_text, self.reply_to)))

        # Email header names are case-insensitive (RFC 2045), so we have to
        # accommodate that when doing comparisons.
        header_names = [key.lower() for key in self.extra_headers]
        if 'date' not in header_names:
            msg['Date'] = formatdate()
        if 'message-id' not in header_names:
            # Use cached DNS_NAME for performance
            msg['Message-ID'] = make_msgid(domain=DNS_NAME)
        for name, value in self.extra_headers.items():
            if name.lower() in ('from', 'to'):  # From and To are already handled
                continue
            msg[name] = value

        return msg
Example #31
0
    def message(self):
        """
        Returns the final message to be sent, including all headers etc. Content and attachments are encrypted using
        GPG in PGP/MIME format (RFC 3156).
        """
        def build_plain_message():
            msg = SafeMIMEText(self.body, self.content_subtype, encoding)
            msg = self._create_message(msg)
            return msg

        def build_version_attachment():
            version_attachment = SafeMIMEText('Version: 1\n',
                                              self.content_subtype, encoding)
            del version_attachment['Content-Type']
            version_attachment.add_header('Content-Type',
                                          'application/pgp-encrypted')
            version_attachment.add_header('Content-Description',
                                          'PGP/MIME Versions Identification')
            return version_attachment

        def build_gpg_attachment():
            gpg_attachment = SafeMIMEText(encrypted_msg, self.content_subtype,
                                          encoding)
            del gpg_attachment['Content-Type']
            gpg_attachment.add_header('Content-Type',
                                      'application/octet-stream',
                                      name=self.gpg_attachment_filename)
            gpg_attachment.add_header('Content-Disposition',
                                      'inline',
                                      filename=self.gpg_attachment_filename)
            gpg_attachment.add_header('Content-Description',
                                      'OpenPGP encrypted message')
            return gpg_attachment

        encoding = self.encoding or settings.DEFAULT_CHARSET

        # build message including attachments as it would also be built without GPG
        msg = build_plain_message()

        # encrypt whole message including attachments
        encrypted_msg = self._encrypt(str(msg))

        # build new message object wrapping the encrypted message
        msg = SafeMIMEMultipart(_subtype=self.encrypted_subtype,
                                encoding=encoding,
                                protocol='application/pgp-encrypted')

        version_attachment = build_version_attachment()
        gpg_attachment = build_gpg_attachment()
        msg.attach(version_attachment)
        msg.attach(gpg_attachment)

        self.extra_headers['Content-Transfer-Encoding'] = '7bit'

        # add headers
        # everything below this line has not been modified when overriding message()
        ############################################################################

        msg['Subject'] = self.subject
        msg['From'] = self.extra_headers.get('From', self.from_email)
        msg['To'] = self.extra_headers.get('To',
                                           ', '.join(map(force_text, self.to)))
        if self.cc:
            msg['Cc'] = ', '.join(map(force_text, self.cc))
        if self.reply_to:
            msg['Reply-To'] = self.extra_headers.get(
                'Reply-To', ', '.join(map(force_text, self.reply_to)))

        # Email header names are case-insensitive (RFC 2045), so we have to
        # accommodate that when doing comparisons.
        header_names = [key.lower() for key in self.extra_headers]
        if 'date' not in header_names:
            msg['Date'] = formatdate()
        if 'message-id' not in header_names:
            # Use cached DNS_NAME for performance
            msg['Message-ID'] = make_msgid(domain=DNS_NAME)
        for name, value in self.extra_headers.items():
            if name.lower() in ('from',
                                'to'):  # From and To are already handled
                continue
            msg[name] = value

        return msg
Example #32
0
 def create_messageid(self, idstring=None):
     idstring = idstring or utils.get_random_string(8)
     return mail.make_msgid(idstring=idstring, domain=self.domain)