mail.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 16 Sep 2015 16:04:17 +0200
changeset 10799 ec97974b9010
parent 10702 f94c812c3669
child 11012 739943455c9d
permissions -rw-r--r--
make sync_schema_props_perms(<computed rtype>) work as expected It currently ends up with an ExecutionError while we want to synchronize permissions. This makes 3.21.1 migration of any application using computed relation crashing. Also, remove pre 3.6 compat code in hooks that prevent living schema update on computed relation's permission changes.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8599
4fabc81cd924 docstring typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8056
diff changeset
     1
# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4835
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
8599
4fabc81cd924 docstring typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8056
diff changeset
    18
"""Common utilies to format / send emails."""
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    19
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    20
__docformat__ = "restructuredtext en"
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    21
2879
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    22
from base64 import b64encode, b64decode
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    23
from time import time
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7815
diff changeset
    24
from email.mime.multipart import MIMEMultipart
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7815
diff changeset
    25
from email.mime.text import MIMEText
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7815
diff changeset
    26
from email.mime.image import MIMEImage
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7815
diff changeset
    27
from email.header import Header
10326
03d98646d57c [mail] include Date header in generated mails (closes #5271058)
Julien Cristau <julien.cristau@logilab.fr>
parents: 9362
diff changeset
    28
from email.utils import formatdate
8056
8909800a8c51 [cleanup] drop some appengine support junk
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
    29
from socket import gethostname
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    30
10701
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    31
from six import PY2, PY3, text_type
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    32
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    33
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    34
def header(ustring):
10701
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    35
    if PY3:
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    36
        return Header(ustring, 'utf-8')
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    37
    return Header(ustring.encode('UTF-8'), 'UTF-8')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    38
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
def addrheader(uaddr, uname=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    40
    # even if an email address should be ascii, encode it using utf8 since
2476
1294a6bdf3bf application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
    41
    # automatic tests may generate non ascii email address
10701
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    42
    if PY2:
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    43
        addr = uaddr.encode('UTF-8')
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    44
    else:
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    45
        addr = uaddr
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    46
    if uname:
10701
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    47
        val = '%s <%s>' % (header(uname).encode(), addr)
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    48
    else:
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    49
        val = addr
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    50
    assert isinstance(val, str)  # bytes in py2, ascii-encoded unicode in py3
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    51
    return val
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    52
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    53
2879
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    54
def construct_message_id(appid, eid, withtimestamp=True):
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    55
    if withtimestamp:
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    56
        addrpart = 'eid=%s&timestamp=%.10f' % (eid, time())
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    57
    else:
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    58
        addrpart = 'eid=%s' % eid
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    59
    # we don't want any equal sign nor trailing newlines
10701
ca3efd72e854 [mail] port to py3k
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10326
diff changeset
    60
    leftpart = b64encode(addrpart.encode('ascii'), b'.-').decode('ascii').rstrip().rstrip('=')
2879
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    61
    return '<%s@%s.%s>' % (leftpart, appid, gethostname())
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    62
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    63
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    64
def parse_message_id(msgid, appid):
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    65
    if msgid[0] == '<':
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    66
        msgid = msgid[1:]
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    67
    if msgid[-1] == '>':
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    68
        msgid = msgid[:-1]
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    69
    try:
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    70
        values, qualif = msgid.split('@')
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    71
        padding = len(values) % 4
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    72
        values = b64decode(str(values + '='*padding), '.-')
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    73
        values = dict(v.split('=') for v in values.split('&'))
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    74
        fromappid, host = qualif.split('.', 1)
7815
2a164a9cf81c [exceptions] stop catching any exception in various places (closes #1942716)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5736
diff changeset
    75
    except Exception:
2879
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    76
        return None
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    77
    if appid != fromappid or host != gethostname():
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    78
        return None
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    79
    return values
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    80
ae26a80c0635 move base NotificationView to cw.common.mail, we may want to use it to send notification from the web ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2476
diff changeset
    81
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    82
def format_mail(uinfo, to_addrs, content, subject="",
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    83
                cc_addrs=(), msgid=None, references=(), config=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    84
    """Sends an Email to 'e_addr' with content 'content', and subject 'subject'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    85
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    86
    to_addrs and cc_addrs are expected to be a list of email address without
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    87
    name
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    88
    """
10702
f94c812c3669 [py3k] unicode → six.text_type
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10701
diff changeset
    89
    assert isinstance(content, text_type), repr(content)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    90
    msg = MIMEText(content.encode('UTF-8'), 'plain', 'UTF-8')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    91
    # safety: keep only the first newline
5579
297b2002a083 fix 978144: exception with view send-email if empty subject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    92
    try:
297b2002a083 fix 978144: exception with view send-email if empty subject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    93
        subject = subject.splitlines()[0]
297b2002a083 fix 978144: exception with view send-email if empty subject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    94
        msg['Subject'] = header(subject)
297b2002a083 fix 978144: exception with view send-email if empty subject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    95
    except IndexError:
297b2002a083 fix 978144: exception with view send-email if empty subject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    96
        pass # no subject
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    97
    if uinfo.get('email'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    98
        email = uinfo['email']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    99
    elif config and config['sender-addr']:
10702
f94c812c3669 [py3k] unicode → six.text_type
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10701
diff changeset
   100
        email = text_type(config['sender-addr'])
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   101
    else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   102
        email = u''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   103
    if uinfo.get('name'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   104
        name = uinfo['name']
9362
2f0129d17fa9 [mail] format_mail copy/paste fix: we want to test sender-name, not sender-addr
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8931
diff changeset
   105
    elif config and config['sender-name']:
10702
f94c812c3669 [py3k] unicode → six.text_type
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10701
diff changeset
   106
        name = text_type(config['sender-name'])
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   107
    else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   108
        name = u''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   109
    msg['From'] = addrheader(email, name)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   110
    if config and config['sender-addr'] and config['sender-addr'] != email:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   111
        appaddr = addrheader(config['sender-addr'], config['sender-name'])
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   112
        msg['Reply-to'] = '%s, %s' % (msg['From'], appaddr)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   113
    elif email:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   114
        msg['Reply-to'] = msg['From']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   115
    if config is not None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   116
        msg['X-CW'] = config.appid
425
cc9e8986d55e sort email addresses and remove doubled ones before sending the email
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 0
diff changeset
   117
    unique_addrs = lambda addrs: sorted(set(addr for addr in addrs if addr is not None))
cc9e8986d55e sort email addresses and remove doubled ones before sending the email
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 0
diff changeset
   118
    msg['To'] = ', '.join(addrheader(addr) for addr in unique_addrs(to_addrs))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   119
    if cc_addrs:
425
cc9e8986d55e sort email addresses and remove doubled ones before sending the email
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 0
diff changeset
   120
        msg['Cc'] = ', '.join(addrheader(addr) for addr in unique_addrs(cc_addrs))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   121
    if msgid:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   122
        msg['Message-id'] = msgid
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   123
    if references:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   124
        msg['References'] = ', '.join(references)
10326
03d98646d57c [mail] include Date header in generated mails (closes #5271058)
Julien Cristau <julien.cristau@logilab.fr>
parents: 9362
diff changeset
   125
    msg['Date'] = formatdate()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   126
    return msg
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   127
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   128
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   129
class HtmlEmail(MIMEMultipart):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   130
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   131
    def __init__(self, subject, textcontent, htmlcontent,
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   132
                 sendermail=None, sendername=None, recipients=None, ccrecipients=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   133
        MIMEMultipart.__init__(self, 'related')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   134
        self['Subject'] = header(subject)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   135
        self.preamble = 'This is a multi-part message in MIME format.'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   136
        # Attach alternative text message
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   137
        alternative = MIMEMultipart('alternative')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   138
        self.attach(alternative)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   139
        msgtext = MIMEText(textcontent.encode('UTF-8'), 'plain', 'UTF-8')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   140
        alternative.attach(msgtext)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   141
        # Attach html message
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   142
        msghtml = MIMEText(htmlcontent.encode('UTF-8'), 'html', 'UTF-8')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   143
        alternative.attach(msghtml)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   144
        if sendermail or sendername:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   145
            self['From'] = addrheader(sendermail, sendername)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   146
        if recipients:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   147
            self['To'] = ', '.join(addrheader(addr) for addr in recipients if addr is not None)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   148
        if ccrecipients:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   149
            self['Cc'] = ', '.join(addrheader(addr) for addr in ccrecipients if addr is not None)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   150
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   151
    def attach_image(self, data, htmlId):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   152
        image = MIMEImage(data)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   153
        image.add_header('Content-ID', '<%s>' % htmlId)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   154
        self.attach(image)