summaryrefslogtreecommitdiff
path: root/postgresqleu/mailqueue/util.py
blob: 94166ed7111a58e75eaf514cfc7015f2194f73e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
from email.utils import formatdate, formataddr, format_datetime
from email.header import Header
from email import encoders
from email.parser import Parser

from postgresqleu.util.context_processors import settings_context

from django.template.loader import get_template
from django.utils import timezone

from .models import QueuedMail


def template_to_string(templatename, attrs={}):
    context = {}
    context.update(attrs)
    context.update(settings_context())
    return get_template(templatename).render(context)


def send_template_mail(sender, receiver, subject, templatename, templateattr={}, attachments=None, bcc=None, sendername=None, receivername=None, suppress_auto_replies=True, is_auto_reply=False, sendat=None):
    send_simple_mail(sender, receiver, subject,
                     template_to_string(templatename, templateattr),
                     attachments, bcc, sendername, receivername,
                     suppress_auto_replies, is_auto_reply, sendat)


def _encoded_email_header(name, email):
    if name:
        return formataddr((str(Header(name, 'utf-8')), email))
    return email


def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=None, sendername=None, receivername=None, suppress_auto_replies=True, is_auto_reply=False, sendat=None):
    # attachment format, each is a tuple of (name, mimetype,contents)
    # content should be *binary* and not base64 encoded, since we need to
    # use the base64 routines from the email library to get a properly
    # formatted output message
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['To'] = _encoded_email_header(receivername, receiver)
    msg['From'] = _encoded_email_header(sendername, sender)
    if sendat is None:
        msg['Date'] = formatdate(localtime=True)
    else:
        msg['Date'] = format_datetime(sendat)
    if suppress_auto_replies:
        # Do our best to set some headers to indicate that auto-replies like out of office
        # messages should not be sent to this email.
        msg['X-Auto-Response-Suppress'] = 'All'
        if is_auto_reply:
            msg['Auto-Submitted'] = 'auto-replied'
        else:
            msg['Auto-Submitted'] = 'auto-generated'

    msg.attach(MIMEText(msgtxt, _charset='utf-8'))

    if attachments:
        for filename, contenttype, content in attachments:
            main, sub = contenttype.split('/')
            part = MIMENonMultipart(main, sub)
            part.set_payload(content)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename)
            encoders.encode_base64(part)
            msg.attach(part)

    # Just write it to the queue, so it will be transactionally rolled back
    QueuedMail(
        sender=sender,
        receiver=receiver,
        subject=subject,
        fullmsg=msg.as_string(),
        sendtime=sendat or timezone.now(),
    ).save()

    # Any bcc is just entered as a separate email
    if bcc:
        if type(bcc) is list or type(bcc) is tuple:
            bcc = set(bcc)
        else:
            bcc = set((bcc, ))

        for b in bcc:
            QueuedMail(
                sender=sender,
                receiver=b,
                subject=subject,
                fullmsg=msg.as_string(),
                sendtime=sendat or timezone.now(),
            ).save()


def send_mail(sender, receiver, subject, fullmsg):
    # Send an email, prepared as the full MIME encoded mail already
    QueuedMail(sender=sender, receiver=receiver, subject=subject, fullmsg=fullmsg).save()


def parse_mail_content(fullmsg):
    # We only try to parse the *first* piece, because we assume
    # all our emails are trivial.
    try:
        parser = Parser()
        parsed_msg = parser.parsestr(fullmsg)
        b = parsed_msg.get_payload(decode=True)
        if b:
            return parsed_msg, b

        pl = parsed_msg.get_payload()
        for p in pl:
            b = p.get_payload(decode=True)
            if b:
                return parsed_msg, b
        return parsed_msg, "Could not find body"
    except Exception as e:
        raise Exception("Failed to get body: %s" % e)


def recursive_parse_attachments_from_message(container):
    if container.get_content_type() == 'multipart/mixed':
        for p in container.get_payload():
            if p.get_params() is None:
                continue
            yield from recursive_parse_attachments_from_message(p)
    elif container.get_content_type() != 'text/plain':
        yield (container.get_filename(), container.get_filename(), container.get_content_type(), container.get_payload(decode=True))