Exemple #1
0
    def get_emails_header(self, attr):
        c = Charset(self.charset)
        c.header_encoding = QP
        c.body_encoding = 0
        r = Charset(self.charset)
        r.header_encoding = 0
        r.body_encoding = 0

        h = Header()
        self.normalize_email_list(attr)
        emails = self.__getattribute__(attr)

        for i in range(len(emails)):
            name, email = emails[i]

            if i:
                h.append(',', r)

            if name:
                name = name.encode(self.charset, 'xmlcharrefreplace')
                h.append(name, r if is7bit(name) else c)
                h.append('<%s>' % email, r)
            else:
                h.append(email, r)

        return h
Exemple #2
0
def create_charset(mime_encoding):
    """Create an appropriate email charset for the given encoding.

    Valid options are 'base64' for Base64 encoding, 'qp' for
    Quoted-Printable, and 'none' for no encoding, in which case mails will
    be sent as 7bit if the content is all ASCII, or 8bit otherwise.
    """
    charset = Charset()
    charset.input_charset = 'utf-8'
    charset.output_charset = 'utf-8'
    charset.input_codec = 'utf-8'
    charset.output_codec = 'utf-8'
    pref = mime_encoding.lower()
    if pref == 'base64':
        charset.header_encoding = BASE64
        charset.body_encoding = BASE64
    elif pref in ('qp', 'quoted-printable'):
        charset.header_encoding = QP
        charset.body_encoding = QP
    elif pref == 'none':
        charset.header_encoding = SHORTEST
        charset.body_encoding = None
    else:
        raise TracError(_("Invalid email encoding setting: %(mime_encoding)s",
                          mime_encoding=mime_encoding))
    return charset
Exemple #3
0
def create_charset(mime_encoding):
    """Create an appropriate email charset for the given encoding.

    Valid options are 'base64' for Base64 encoding, 'qp' for
    Quoted-Printable, and 'none' for no encoding, in which case mails will
    be sent as 7bit if the content is all ASCII, or 8bit otherwise.
    """
    charset = Charset()
    charset.input_charset = 'utf-8'
    charset.output_charset = 'utf-8'
    charset.input_codec = 'utf-8'
    charset.output_codec = 'utf-8'
    pref = mime_encoding.lower()
    if pref == 'base64':
        charset.header_encoding = BASE64
        charset.body_encoding = BASE64
    elif pref in ('qp', 'quoted-printable'):
        charset.header_encoding = QP
        charset.body_encoding = QP
    elif pref == 'none':
        charset.header_encoding = SHORTEST
        charset.body_encoding = None
    else:
        raise TracError(
            _("Invalid email encoding setting: %(mime_encoding)s",
              mime_encoding=mime_encoding))
    return charset
Exemple #4
0
    def get_emails_header(self, attr):
        c = Charset(self.charset)
        c.header_encoding = QP
        c.body_encoding = 0
        r = Charset(self.charset)
        r.header_encoding = 0
        r.body_encoding = 0

        h = Header()
        self.normalize_email_list(attr)
        emails = self.__getattribute__(attr)

        for i in range(len(emails)):
            name, email = emails[i]

            if i:
                h.append(',', r)

            if name:
                name = name.encode(self.charset, 'xmlcharrefreplace')
                h.append(name, r if is7bit(name) else c)
                h.append('<%s>' % email, r)
            else:
                h.append(email, r)
        return h
Exemple #5
0
    def as_message(self, escape_addresses=True):
        # http://wordeology.com/computer/how-to-send-good-unicode-email-with-python.html
        # http://stackoverflow.com/questions/31714221/how-to-send-an-email-with-quoted
        # http://stackoverflow.com/questions/9403265/how-do-i-use-python/9509718#9509718
        charset = Charset('utf-8')
        charset.header_encoding = QP
        charset.body_encoding = QP
        msg = MIMEMultipart()

        # Headers
        unixfrom = "From %s %s" % (
            self.sender.address, self.archived_date.strftime("%c"))
        header_from = self.sender.address
        if self.sender.name and self.sender.name != self.sender.address:
            header_from = "%s <%s>" % (self.sender.name, header_from)
        header_to = self.mailinglist.name
        if escape_addresses:
            header_from = header_from.replace("@", " at ")
            header_to = header_to.replace("@", " at ")
            unixfrom = unixfrom.replace("@", " at ")
        msg.set_unixfrom(unixfrom)
        headers = (
            ("From", header_from),
            ("To", header_to),
            ("Subject", self.subject),
            )
        for header_name, header_value in headers:
            if not header_value:
                continue
            try:
                msg[header_name] = header_value.encode('ascii')
            except UnicodeEncodeError:
                msg[header_name] = Header(
                    header_value.encode('utf-8'), charset).encode()
        tz = get_fixed_timezone(self.timezone)
        header_date = self.date.astimezone(tz).replace(microsecond=0)
        # Date format: http://tools.ietf.org/html/rfc5322#section-3.3
        msg["Date"] = header_date.strftime("%a, %d %b %Y %H:%M:%S %z")
        msg["Message-ID"] = "<%s>" % self.message_id
        if self.in_reply_to:
            msg["In-Reply-To"] = self.in_reply_to

        # Body
        content = self.ADDRESS_REPLACE_RE.sub(r"\1(a)\2", self.content)
        # Don't use MIMEText, it won't encode to quoted-printable
        textpart = MIMENonMultipart("text", "plain", charset='utf-8')
        textpart.set_payload(content, charset=charset)
        msg.attach(textpart)

        # Attachments
        for attachment in self.attachments.order_by("counter"):
            mimetype = attachment.content_type.split('/', 1)
            part = MIMEBase(mimetype[0], mimetype[1])
            part.set_payload(attachment.content)
            encode_base64(part)
            part.add_header('Content-Disposition', 'attachment',
                            filename=attachment.name)
            msg.attach(part)

        return msg
Exemple #6
0
    def format(self, events, encoding="utf-8"):
        parts = list()
        data = templates.Template.format(self, parts, events)
        parsed = message_from_string(data.encode(encoding))

        charset = Charset(encoding)
        charset.header_encoding = QP

        msg = MIMEMultipart()
        msg.set_charset(charset)
        for key, value in msg.items():
            del parsed[key]
        for key, value in parsed.items():
            msg[key] = value

        for encoded in ["Subject", "Comment"]:
            if encoded not in msg:
                continue
            value = charset.header_encode(msg[encoded])
            del msg[encoded]
            msg[encoded] = value

        del msg['Content-Transfer-Encoding']
        msg['Content-Transfer-Encoding'] = '7bit'

        msg.attach(MIMEText(parsed.get_payload(), "plain", encoding))
        for part in parts:
            msg.attach(part)
        return msg
Exemple #7
0
    def format(self, events, encoding="utf-8"):
        parts = list()
        data = templates.Template.format(self, parts, events)
        parsed = message_from_string(data.encode(encoding))

        charset = Charset(encoding)
        charset.header_encoding = QP

        msg = MIMEMultipart()
        msg.set_charset(charset)
        for key, value in msg.items():
            del parsed[key]
        for key, value in parsed.items():
            msg[key] = value

        for encoded in ["Subject", "Comment"]:
            if encoded not in msg:
                continue
            value = charset.header_encode(msg[encoded])
            del msg[encoded]
            msg[encoded] = value

        del msg["Content-Transfer-Encoding"]
        msg["Content-Transfer-Encoding"] = "7bit"

        msg.attach(MIMEText(parsed.get_payload(), "plain", encoding))
        for part in parts:
            msg.attach(part)
        return msg
Exemple #8
0
    def format(self, events, encoding="utf-8"):
        from email import message_from_string
        from email.mime.multipart import MIMEMultipart
        from email.mime.text import MIMEText
        from email.charset import Charset, QP
        from email.utils import formatdate, make_msgid

        parts = list()
        data = templates.Template.format(self, parts, events)
        parsed = message_from_string(data.encode(encoding))

        charset = Charset(encoding)
        charset.header_encoding = QP

        msg = MIMEMultipart()
        msg.set_charset(charset)
        for key, value in msg.items():
            del parsed[key]
        for key, value in parsed.items():
            msg[key] = value

        for encoded in ["Subject", "Comment"]:
            if encoded not in msg:
                continue
            value = charset.header_encode(msg[encoded])
            del msg[encoded]
            msg[encoded] = value

        del msg['Content-Transfer-Encoding']
        msg['Content-Transfer-Encoding'] = '7bit'

        msg.attach(MIMEText(parsed.get_payload(), "plain", encoding))
        for part in parts:
            msg.attach(part)
        return msg
def sendmail(server, from_, to, message):
    if not isinstance(to, list):
        to = [to]

    charset = Charset('UTF-8')
    charset.header_encoding = QP
    charset.body_encoding = QP

    msg = email.message_from_string(message)
    msg.set_charset(charset)

    server.sendmail(from_, to, msg.as_string())
Exemple #10
0
def write_patch_file(filename, commit_info, diff):
    """Write patch file"""
    if not diff:
        gbp.log.debug("I won't generate empty diff %s" % filename)
        return None
    try:
        with open(filename, 'wb') as patch:
            msg = Message()
            charset = Charset('utf-8')
            charset.body_encoding = None
            charset.header_encoding = QP

            # Write headers
            name = commit_info['author']['name']
            email = commit_info['author']['email']
            # Git compat: put name in quotes if special characters found
            if re.search(r'[,.@()\[\]\\\:;]', name):
                name = '"%s"' % name
            from_header = Header(header_name='from')
            try:
                from_header.append(name, 'us-ascii')
            except UnicodeDecodeError:
                from_header.append(name, charset)
            from_header.append('<%s>' % email)
            msg['From'] = from_header
            date = commit_info['author'].datetime
            datestr = date.strftime('%a, %-d %b %Y %H:%M:%S %z')
            msg['Date'] = Header(datestr, 'us-ascii', 'date')
            subject_header = Header(header_name='subject')
            try:
                subject_header.append(commit_info['subject'], 'us-ascii')
            except UnicodeDecodeError:
                subject_header.append(commit_info['subject'], charset)
            msg['Subject'] = subject_header
            # Write message body
            if commit_info['body']:
                # Strip extra linefeeds
                body = commit_info['body'].rstrip() + '\n'
                try:
                    msg.set_payload(body.encode('us-ascii'))
                except (UnicodeEncodeError):
                    msg.set_payload(body, charset)
            policy = Compat32(max_line_length=77)
            patch.write(msg.as_bytes(unixfrom=False, policy=policy))

            # Write diff
            patch.write(b'---\n')
            patch.write(diff)
    except IOError as err:
        raise GbpError('Unable to create patch file: %s' % err)
    return filename
Exemple #11
0
def write_patch_file(filename, commit_info, diff):
    """Write patch file"""
    if not diff:
        gbp.log.debug("I won't generate empty diff %s" % filename)
        return None
    try:
        with open(filename, 'wb') as patch:
            msg = Message()
            charset = Charset('utf-8')
            charset.body_encoding = None
            charset.header_encoding = QP

            # Write headers
            name = commit_info['author']['name']
            email = commit_info['author']['email']
            # Git compat: put name in quotes if special characters found
            if re.search("[,.@()\[\]\\\:;]", name):
                name = '"%s"' % name
            from_header = Header(header_name='from')
            try:
                from_header.append(name, 'us-ascii')
            except UnicodeDecodeError:
                from_header.append(name, charset)
            from_header.append('<%s>' % email)
            msg['From'] = from_header
            date = commit_info['author'].datetime
            datestr = date.strftime('%a, %-d %b %Y %H:%M:%S %z')
            msg['Date'] = Header(datestr, 'us-ascii', 'date')
            subject_header = Header(header_name='subject')
            try:
                subject_header.append(commit_info['subject'], 'us-ascii')
            except UnicodeDecodeError:
                subject_header.append(commit_info['subject'], charset)
            msg['Subject'] = subject_header
            # Write message body
            if commit_info['body']:
                # Strip extra linefeeds
                body = commit_info['body'].rstrip() + '\n'
                try:
                    msg.set_payload(body.encode('us-ascii'))
                except (UnicodeEncodeError):
                    msg.set_payload(body, charset)
            patch.write(
                msg.as_string(unixfrom=False, maxheaderlen=77).encode('utf-8'))

            # Write diff
            patch.write(b'---\n')
            patch.write(diff)
    except IOError as err:
        raise GbpError('Unable to create patch file: %s' % err)
    return filename
 def _make_charset(self):
     charset = Charset()
     charset.input_charset = 'utf-8'
     pref = self.mime_encoding.lower()
     if pref == 'base64':
         charset.header_encoding = BASE64
         charset.body_encoding = BASE64
         charset.output_charset = 'utf-8'
         charset.input_codec = 'utf-8'
         charset.output_codec = 'utf-8'
     elif pref in ['qp', 'quoted-printable']:
         charset.header_encoding = QP
         charset.body_encoding = QP
         charset.output_charset = 'utf-8'
         charset.input_codec = 'utf-8'
         charset.output_codec = 'utf-8'
     elif pref == 'none':
         charset.header_encoding = None
         charset.body_encoding = None
         charset.input_codec = None
         charset.output_charset = 'ascii'
     else:
         raise TracError(_('Invalid email encoding setting: %s' % pref))
     return charset
Exemple #13
0
    def _mail(self, fromaddr, to, subject, payload):

        # prepare
        charset = Charset("utf-8")
        charset.header_encoding = QP
        charset.body_encoding = QP

        # create method and set headers
        msg = Message()
        msg.set_payload(payload.encode("utf8"))
        msg.set_charset(charset)
        msg['Subject'] = Header(subject, "utf8")
        msg['From'] = fromaddr
        msg['To'] = to

        self.server.connect()
        self.server.sendmail(fromaddr, [to], msg.as_string())
        self.server.quit()
Exemple #14
0
    def _mail(self, fromaddr, to, subject, payload):

        # prepare
        charset = Charset("utf-8")
        charset.header_encoding = QP
        charset.body_encoding = QP

        # create method and set headers
        msg = Message()
        msg.set_payload(payload.encode("utf8"))
        msg.set_charset(charset)
        msg['Subject'] = Header(subject, "utf8")
        msg['From'] = fromaddr
        msg['To'] = to

        self.server.connect()
        self.server.sendmail(fromaddr, [to], msg.as_string())
        self.server.quit()
Exemple #15
0
def write_patch_file(filename, commit_info, diff):
    """Write patch file"""
    if not diff:
        gbp.log.debug("I won't generate empty diff %s" % filename)
        return None
    try:
        with open(filename, "w") as patch:
            msg = Message()
            charset = Charset("utf-8")
            charset.body_encoding = None
            charset.header_encoding = QP

            # Write headers
            name = commit_info["author"]["name"]
            email = commit_info["author"]["email"]
            # Git compat: put name in quotes if special characters found
            if re.search("[,.@()\[\]\\\:;]", name):
                name = '"%s"' % name
            from_header = Header(unicode(name, "utf-8"), charset, 77, "from")
            from_header.append(unicode("<%s>" % email))
            msg["From"] = from_header
            date = commit_info["author"].datetime
            datestr = date.strftime("%a, %-d %b %Y %H:%M:%S %z")
            msg["Date"] = Header(unicode(datestr, "utf-8"), charset, 77, "date")
            msg["Subject"] = Header(unicode(commit_info["subject"], "utf-8"), charset, 77, "subject")
            # Write message body
            if commit_info["body"]:
                # Strip extra linefeeds
                body = commit_info["body"].rstrip() + "\n"
                try:
                    msg.set_payload(body.encode("ascii"))
                except UnicodeDecodeError:
                    msg.set_payload(body, charset)
            patch.write(msg.as_string(unixfrom=False))

            # Write diff
            patch.write("---\n")
            patch.write(diff)
    except IOError as err:
        raise GbpError("Unable to create patch file: %s" % err)
    return filename
Exemple #16
0
def sendmail(subject,
             text,
             to=None,
             cc=None,
             bcc=None,
             mail_from=None,
             html=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    :param subject: subject of email
    :type subject: unicode
    :param text: email body text
    :type text: unicode
    :param to: recipients
    :type to: list
    :param cc: recipients (CC)
    :type cc: list
    :param bcc: recipients (BCC)
    :type bcc: list
    :param mail_from: override default mail_from
    :type mail_from: unicode
    :param html: html email body text
    :type html: unicode

    :rtype: tuple
    :returns: (is_ok, Description of error or OK message)
    """
    import smtplib
    import socket
    from email.message import Message
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.charset import Charset, QP
    from email.utils import formatdate, make_msgid

    cfg = app.cfg
    if not cfg.mail_enabled:
        return (
            0,
            _("Contact administrator: cannot send password recovery e-mail "
              "because mail configuration is incomplete."))
    mail_from = mail_from or cfg.mail_from

    logging.debug("send mail, from: {0!r}, subj: {1!r}".format(
        mail_from, subject))
    logging.debug("send mail, to: {0!r}".format(to))

    if not to and not cc and not bcc:
        return 1, _("No recipients, nothing to do")

    subject = subject.encode(CHARSET)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(CHARSET)

    # Create a message using CHARSET and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    text_msg = Message()
    charset = Charset(CHARSET)
    charset.header_encoding = QP
    charset.body_encoding = QP
    text_msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    text_msg.set_payload('=')
    if text_msg.as_string().endswith('='):
        text = charset.body_encode(text)

    text_msg.set_payload(text)

    if html:
        msg = MIMEMultipart('alternative')
        msg.attach(text_msg)
        html = html.encode(CHARSET)
        html_msg = MIMEText(html, 'html')
        html_msg.set_charset(charset)
        msg.attach(html_msg)
    else:
        msg = text_msg

    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    if to:
        msg['To'] = ','.join(to)
    if cc:
        msg['CC'] = ','.join(cc)
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)
    # See RFC 3834 section 5:
    msg['Auto-Submitted'] = 'auto-generated'

    if cfg.mail_sendmail:
        if bcc:
            # Set the BCC.  This will be stripped later by sendmail.
            msg['BCC'] = ','.join(bcc)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug(
                "trying to send mail (smtp) via smtp server '{0}'".format(
                    cfg.mail_smarthost))
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                # server.set_debuglevel(1)
                if cfg.mail_username is not None and cfg.mail_password is not None:
                    try:  # try to do TLS
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug(
                                "tls connection to smtp server established")
                    except Exception:
                        logging.debug(
                            "could not establish a tls connection to smtp server, continuing without tls"
                        )
                    logging.debug(
                        "trying to log in to smtp server using account '{0}'".
                        format(cfg.mail_username))
                    server.login(cfg.mail_username, cfg.mail_password)
                server.sendmail(mail_from,
                                (to or []) + (cc or []) + (bcc or []),
                                msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except smtplib.SMTPException as e:
            logging.exception("smtp mail failed with an exception.")
            return 0, str(e)
        except (os.error, socket.error) as e:
            logging.exception("smtp mail failed with an exception.")
            return (
                0,
                _("Connection to mailserver '%(server)s' failed: %(reason)s",
                  server=cfg.mail_smarthost,
                  reason=str(e)))
    else:
        try:
            logging.debug("trying to send mail (sendmail)")
            sendmailp = os.popen(cfg.mail_sendmail, "w")
            # msg contains everything we need, so this is a simple write
            sendmailp.write(msg.as_string())
            sendmail_status = sendmailp.close()
            if sendmail_status:
                logging.error("sendmail failed with status: {0!s}".format(
                    sendmail_status))
                return 0, str(sendmail_status)
        except Exception:
            logging.exception("sendmail failed with an exception.")
            return 0, _("Mail not sent")

    logging.debug("Mail sent successfully")
    return 1, _("Mail sent successfully")
Exemple #17
0
def sendmail(request, to, subject, text, mail_from=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    @param request: the request object
    @param to: recipients (list)
    @param subject: subject of email (unicode)
    @param text: email body text (unicode)
    @param mail_from: override default mail_from
    @type mail_from: unicode
    @rtype: tuple
    @return: (is_ok, Description of error or OK message)
    """
    import smtplib, socket
    from email.message import Message
    from email.charset import Charset, QP
    from email.utils import formatdate, make_msgid

    _ = request.getText
    cfg = request.cfg
    mail_from = mail_from or cfg.mail_from

    logging.debug("send mail, from: %r, subj: %r" % (mail_from, subject))
    logging.debug("send mail, to: %r" % (to, ))

    if not to:
        return (1, _("No recipients, nothing to do"))

    subject = subject.encode(config.charset)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(config.charset)

    # Create a message using config.charset and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    msg = Message()
    charset = Charset(config.charset)
    charset.header_encoding = QP
    charset.body_encoding = QP
    msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    msg.set_payload('=')
    if msg.as_string().endswith('='):
        text = charset.body_encode(text)

    msg.set_payload(text)

    # Create message headers
    # Don't expose emails addreses of the other subscribers, instead we
    # use the same mail_from, e.g. u"Jürgen Wiki <*****@*****.**>"
    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    msg['To'] = address
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)
    # See RFC 3834 section 5:
    msg['Auto-Submitted'] = 'auto-generated'

    if cfg.mail_sendmail:
        # Set the BCC.  This will be stripped later by sendmail.
        msg['BCC'] = ','.join(to)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug("trying to send mail (smtp) via smtp server '%s'" %
                          cfg.mail_smarthost)
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                #server.set_debuglevel(1)
                if cfg.mail_login:
                    user, pwd = cfg.mail_login.split()
                    try:  # try to do tls
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug(
                                "tls connection to smtp server established")
                    except:
                        logging.debug(
                            "could not establish a tls connection to smtp server, continuing without tls"
                        )
                    logging.debug(
                        "trying to log in to smtp server using account '%s'" %
                        user)
                    server.login(user, pwd)
                server.sendmail(mail_from, to, msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except UnicodeError, e:
            logging.exception("unicode error [%r -> %r]" % (
                mail_from,
                to,
            ))
            return (0, str(e))
        except smtplib.SMTPException, e:
            logging.exception("smtp mail failed with an exception.")
            return (0, str(e))
Exemple #18
0
    def as_message(self, escape_addresses=True):
        # http://wordeology.com/computer/how-to-send-good-unicode-email-with-python.html
        # http://stackoverflow.com/questions/31714221/how-to-send-an-email-with-quoted
        # http://stackoverflow.com/questions/9403265/how-do-i-use-python/9509718#9509718
        charset = Charset('utf-8')
        charset.header_encoding = QP
        charset.body_encoding = QP
        msg = MIMEMultipart()

        # Headers
        unixfrom = "From %s %s" % (self.sender.address,
                                   self.archived_date.strftime("%c"))
        header_from = self.sender.address
        if self.sender_name and self.sender_name != self.sender.address:
            header_from = "%s <%s>" % (self.sender_name, header_from)
        header_to = self.mailinglist.name
        if escape_addresses:
            header_from = header_from.replace("@", " at ")
            header_to = header_to.replace("@", " at ")
            unixfrom = unixfrom.replace("@", " at ")
        msg.set_unixfrom(unixfrom)
        headers = (
            ("From", header_from),
            ("To", header_to),
            ("Subject", self.subject),
        )
        for header_name, header_value in headers:
            if not header_value:
                continue
            try:
                msg[header_name] = header_value.encode('ascii')
            except UnicodeEncodeError:
                msg[header_name] = Header(header_value.encode('utf-8'),
                                          charset).encode()
        tz = get_fixed_timezone(self.timezone)
        header_date = self.date.astimezone(tz).replace(microsecond=0)
        # Date format: http://tools.ietf.org/html/rfc5322#section-3.3
        msg["Date"] = header_date.strftime("%a, %d %b %Y %H:%M:%S %z")
        msg["Message-ID"] = "<%s>" % self.message_id
        if self.in_reply_to:
            msg["In-Reply-To"] = self.in_reply_to

        # Body
        content = self.ADDRESS_REPLACE_RE.sub(r"\1(a)\2", self.content)
        # Don't use MIMEText, it won't encode to quoted-printable
        textpart = MIMENonMultipart("text", "plain", charset='utf-8')
        textpart.set_payload(content, charset=charset)
        msg.attach(textpart)

        # Attachments
        for attachment in self.attachments.order_by("counter"):
            mimetype = attachment.content_type.split('/', 1)
            part = MIMEBase(mimetype[0], mimetype[1])
            part.set_payload(attachment.content)
            encode_base64(part)
            part.add_header('Content-Disposition',
                            'attachment',
                            filename=attachment.name)
            msg.attach(part)

        return msg
Exemple #19
0
    def send(self, emails):
        if isinstance(emails, Email):
            emails = [emails]
        if len([e for e in emails if e.__class__ != Email]):
            raise TypeError('emails must be Email or list of Email instances')

        smtpclass = SMTP_SSL if self.ssl else SMTP
        if self.server == 'localhost':
            smtp = smtpclass(self.server)
        else:
            smtp = smtpclass(self.server, self.port)
        if self.tls:
            smtp.starttls()
        if self.login and self.password:
            smtp.login(self.login, self.password)
        for email in emails:
            c = Charset(email.charset)
            c.header_encoding = QP
            c.body_encoding = 0
            r = Charset(email.charset)
            r.header_encoding = 0
            r.body_encoding = 0

            email.normalize_email_list('rcpt')
            email.normalize_email_list('cc')
            email.normalize_email_list('bcc')
            mime1, mime2 = email.mimetype.split('/')
            mainpart = MIMEBase(mime1, mime2)
            if not email.force_7bit:
                mainpart.set_param('charset', email.charset)

            if len(email.attachments):
                message = MIMEMultipart('mixed')
                message.attach(mainpart)
                del mainpart['mime-version']
            else:
                message = mainpart

            message['Date'] = datetime.datetime.now().strftime(
                '%a, %d %b %Y %H:%M:%S') + (" +%04d" % (time.timezone/-36,))

            h = Header(maxlinelen=1000) # FIXME: what is correct max length?
            fromname = self.fromname.encode(email.charset, 'xmlcharrefreplace')
            h.append(fromname, r if is7bit(fromname) else c)
            h.append('<%s>' % self.email, r)
            message['From'] = h

            message['To'] = email.get_emails_header('rcpt')
            if len(email.cc):
                message['CC'] = email.get_emails_header('cc')
            if len(email.bcc):
                message['BCC'] = email.get_emails_header('bcc')

            subject = email.subject.encode(email.charset, 'xmlcharrefreplace')
            message['Subject'] = Header(subject, r if is7bit(subject) else c)

            if email.reply_to:
                message['Reply-To'] = email.get_emails_header('reply_to')

            if email.force_7bit:
                body = email.body.encode('ascii', 'xmlcharrefreplace')
            else:
                body = email.body.encode(email.charset, 'xmlcharrefreplace')
            mainpart.set_payload(body)

            if is7bit(body):
                mainpart['Content-Transfer-Encoding'] = '7bit'
            else:
                encode_quopri(mainpart)

            for attachment in email.attachments:
                if attachment.__class__ != Attachment:
                    raise TypeError("invalid attachment")

                mimetype = attachment.mimetype
                if not mimetype:
                    mimetype, encoding = guess_type(attachment.filename)
                    if not mimetype:
                        mimetype = 'application/octet-stream'
                mime1, mime2 = mimetype.split('/')
                part = MIMEBase(mime1, mime2)

                # using newer rfc2231 (not supported by Outlook):
                # part.set_param('name', attachment.filename.encode('utf-8'), charset = 'utf-8')

                # hack: using deprecated rfc2047 - supported by Outlook:
                part.set_param('name', str(Header(attachment.filename)))
                del part['mime-version']

                if attachment.id:
                    part['Content-Disposition'] = 'inline'
                else:
                    part['Content-Disposition'] = 'attachment'

                # using newer rfc2231 (not supported by Outlook):
                # part.set_param('filename',
                #                attachment.filename.encode('utf-8'),
                #                'Content-Disposition',
                #                charset = 'utf-8')

                # hack: using deprecated rfc2047 - supported by Outlook:
                part.set_param('filename',
                               str(Header(attachment.filename)),
                               'Content-Disposition')
                if attachment.id:
                    part['Content-ID'] = '<%s>' % attachment.id

                part.set_payload(attachment.content)
                encode_base64(part)

                # Do this AFTER encode_base64(part), or Content-Transfer-Encoding header will duplicate,
                # or even happen 2 times with different values.
                if attachment.charset:
                    part.set_charset(attachment.charset)

                message.attach(part)

            smtp.sendmail(self.email, [rcpt[1] for rcpt in email.rcpt] +
                          [cc[1] for cc in email.cc] +
                          [bcc[1] for bcc in email.bcc], message.as_string())

        smtp.quit()
Exemple #20
0
def sendmail(subject, text, to=None, cc=None, bcc=None, mail_from=None, html=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    :param subject: subject of email
    :type subject: unicode
    :param text: email body text
    :type text: unicode
    :param to: recipients
    :type to: list
    :param cc: recipients (CC)
    :type cc: list
    :param bcc: recipients (BCC)
    :type bcc: list
    :param mail_from: override default mail_from
    :type mail_from: unicode
    :param html: html email body text
    :type html: unicode

    :rtype: tuple
    :returns: (is_ok, Description of error or OK message)
    """
    import smtplib
    import socket
    from email.message import Message
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.charset import Charset, QP
    from email.utils import formatdate, make_msgid

    cfg = app.cfg
    if not cfg.mail_enabled:
        return (0, _("Contact administrator: cannot send password recovery e-mail "
                     "because mail configuration is incomplete."))
    mail_from = mail_from or cfg.mail_from

    logging.debug("send mail, from: {0!r}, subj: {1!r}".format(mail_from, subject))
    logging.debug("send mail, to: {0!r}".format(to))

    if not to and not cc and not bcc:
        return 1, _("No recipients, nothing to do")

    subject = subject.encode(CHARSET)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(CHARSET)

    # Create a message using CHARSET and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    text_msg = Message()
    charset = Charset(CHARSET)
    charset.header_encoding = QP
    charset.body_encoding = QP
    text_msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    text_msg.set_payload('=')
    if text_msg.as_string().endswith('='):
        text = charset.body_encode(text)

    text_msg.set_payload(text)

    if html:
        msg = MIMEMultipart('alternative')
        msg.attach(text_msg)
        html = html.encode(CHARSET)
        html_msg = MIMEText(html, 'html')
        html_msg.set_charset(charset)
        msg.attach(html_msg)
    else:
        msg = text_msg

    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    if to:
        msg['To'] = ','.join(to)
    if cc:
        msg['CC'] = ','.join(cc)
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)
    # See RFC 3834 section 5:
    msg['Auto-Submitted'] = 'auto-generated'

    if cfg.mail_sendmail:
        if bcc:
            # Set the BCC.  This will be stripped later by sendmail.
            msg['BCC'] = ','.join(bcc)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug("trying to send mail (smtp) via smtp server '{0}'".format(cfg.mail_smarthost))
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                #server.set_debuglevel(1)
                if cfg.mail_username is not None and cfg.mail_password is not None:
                    try:  # try to do TLS
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug("tls connection to smtp server established")
                    except:
                        logging.debug("could not establish a tls connection to smtp server, continuing without tls")
                    logging.debug("trying to log in to smtp server using account '{0}'".format(cfg.mail_username))
                    server.login(cfg.mail_username, cfg.mail_password)
                server.sendmail(mail_from, (to or []) + (cc or []) + (bcc or []), msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except smtplib.SMTPException as e:
            logging.exception("smtp mail failed with an exception.")
            return 0, str(e)
        except (os.error, socket.error) as e:
            logging.exception("smtp mail failed with an exception.")
            return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s",
                    server=cfg.mail_smarthost,
                    reason=str(e)
            ))
    else:
        try:
            logging.debug("trying to send mail (sendmail)")
            sendmailp = os.popen(cfg.mail_sendmail, "w")
            # msg contains everything we need, so this is a simple write
            sendmailp.write(msg.as_string())
            sendmail_status = sendmailp.close()
            if sendmail_status:
                logging.error("sendmail failed with status: {0!s}".format(sendmail_status))
                return 0, str(sendmail_status)
        except:
            logging.exception("sendmail failed with an exception.")
            return 0, _("Mail not sent")

    logging.debug("Mail sent successfully")
    return 1, _("Mail sent successfully")
def send_email_report(self,
                      _id,
                      subject,
                      sender,
                      recipients,
                      text_body='',
                      html_body='',
                      cc=None,
                      bcc=None,
                      attachments=None,
                      txt_template='analytics_scheduled_report.txt',
                      html_template='analytics_scheduled_report.html'):
    lock_id = 'analytics_email:{}'.format(str(_id))
    if not lock(lock_id, expire=120):
        return

    try:
        charset = Charset('utf-8')
        charset.header_encoding = QP
        charset.body_encoding = QP

        msg = AnalyticsMessage(subject,
                               sender=sender,
                               recipients=recipients,
                               cc=cc,
                               bcc=bcc,
                               body=text_body,
                               charset=charset)

        reports = []

        if attachments is not None:
            for attachment in attachments:
                try:
                    uuid = str(uuid4())
                    if attachment.get('mimetype') == MIME_TYPES.HTML:
                        reports.append({
                            'id': uuid,
                            'type': 'html',
                            'html': attachment.get('file')
                        })
                    else:
                        msg.attach(filename=attachment.get('filename'),
                                   content_type='{}; name="{}"'.format(
                                       attachment.get('mimetype'),
                                       attachment.get('filename')),
                                   data=b64decode(attachment.get('file')),
                                   disposition='attachment',
                                   headers={
                                       'Content-ID': '<{}>'.format(uuid),
                                       'X-Attachment-Id': uuid
                                   }.items())

                        reports.append({
                            'id': uuid,
                            'type': 'image',
                            'filename': attachment.get('filename'),
                            'width': attachment.get('width')
                        })

                        msg.body += '\n[image: {}]'.format(
                            attachment.get('filename'))
                except Exception as e:
                    logger.error('Failed to generate attachment.')
                    logger.exception(e)

        msg.body = render_template(txt_template,
                                   text_body=text_body,
                                   reports=reports)

        msg.html = render_template(html_template,
                                   html_body=html_body.replace(
                                       '\r', '').replace('\n', '<br>'),
                                   reports=reports)

        return app.mail.send(msg)
    except Exception as e:
        logger.error('Failed to send report email. Error: {}'.format(str(e)))
        logger.exception(e)
    finally:
        unlock(lock_id, remove=True)
Exemple #22
0
    def send(self, emails):
        if isinstance(emails, Email):
            emails = [emails]
        if len([e for e in emails if e.__class__ != Email]):
            raise TypeError('emails must be Email or list of Email instances')

        smtpclass = SMTP_SSL if self.ssl else SMTP
        if self.server == 'localhost':
            smtp = smtpclass(self.server)
        else:
            smtp = smtpclass(self.server, self.port)
        if self.login and self.password:
            smtp.login(self.login, self.password)
        for email in emails:
            c = Charset(email.charset)
            c.header_encoding = QP
            c.body_encoding = 0
            r = Charset(email.charset)
            r.header_encoding = 0
            r.body_encoding = 0

            mime1, mime2 = email.mimetype.split('/')
            mainpart = MIMEBase(mime1, mime2)
            if not email.force_7bit:
                mainpart.set_param('charset', email.charset)

            if len(email.attachments):
                message = MIMEMultipart('mixed')
                message.attach(mainpart)
                del mainpart['mime-version']
            else:
                message = mainpart

            message['Date'] = datetime.datetime.now().strftime(
                '%a, %d %b %Y %H:%M:%S') + (" +%04d" % (time.timezone / -36, ))

            h = Header()
            fromname = self.fromname.encode(email.charset, 'xmlcharrefreplace')
            h.append(fromname, r if is7bit(fromname) else c)
            h.append('<%s>' % self.email, r)
            message['From'] = h

            message['To'] = email.get_emails_header('rcpt')
            if len(email.cc):
                message['CC'] = email.get_emails_header('cc')
            if len(email.bcc):
                message['BCC'] = email.get_emails_header('bcc')

            subject = email.subject.encode(email.charset, 'xmlcharrefreplace')
            message['Subject'] = Header(subject, r if is7bit(subject) else c)

            if email.force_7bit:
                body = email.body.encode('ascii', 'xmlcharrefreplace')
            else:
                body = email.body.encode(email.charset, 'xmlcharrefreplace')
            mainpart.set_payload(body)

            for hn, hv in email.headers.items():
                if hn == 'X-Mailgun-Campaign-Tag':
                    hn = 'X-Mailgun-Tag'
                message[hn] = hv

            if is7bit(body):
                mainpart['Content-Transfer-Encoding'] = '7bit'
            else:
                encode_quopri(mainpart)

            for attachment in email.attachments:
                if attachment.__class__ != Attachment:
                    raise TypeError("invalid attachment")

                mimetype = attachment.mimetype
                if not mimetype:
                    mimetype, encoding = guess_type(attachment.filename)
                    if not mimetype:
                        mimetype = 'application/octet-stream'
                mime1, mime2 = mimetype.split('/')
                part = MIMEBase(mime1, mime2)

                # using newer rfc2231 (not supported by Outlook):
                # part.set_param('name', attachment.filename.encode('utf-8'), charset = 'utf-8')

                # hack: using deprecated rfc2047 - supported by Outlook:
                part.set_param('name', str(Header(attachment.filename)))
                del part['mime-version']

                if attachment.id:
                    part['Content-Disposition'] = 'inline'
                else:
                    part['Content-Disposition'] = 'attachment'

                # using newer rfc2231 (not supported by Outlook):
                # part.set_param('filename',
                #                attachment.filename.encode('utf-8'),
                #                'Content-Disposition',
                #                charset = 'utf-8')

                # hack: using deprecated rfc2047 - supported by Outlook:
                part.set_param('filename', str(Header(attachment.filename)),
                               'Content-Disposition')

                if attachment.id:
                    part['Content-ID'] = '<%s>' % attachment.id

                part.set_payload(attachment.content)
                encode_base64(part)

                message.attach(part)

            emails = email.rcpt + email.cc + email.bcc
            smtp.sendmail(self.email, [email for _, email in emails],
                          message.as_string())

        smtp.quit()