Esempio n. 1
0
File: mail.py Progetto: zxfly/trac
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
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 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
Esempio n. 6
0
 def get_text_message(self, _charset='utf-8', _subtype='plain'):
     message = MIMENonMultipart('text', _subtype)
     cs = Charset(_charset)
     if cs.body_encoding == charset.BASE64:
         cs.body_encoding = charset.QP
     message.set_charset(cs)
     del message['Content-Transfer-Encoding']
     return message
Esempio n. 7
0
        def send_report(self, short_description, additional_description, title,
                        report):
            # Create message container - the correct MIME type is multipart/mixed to allow attachment.
            full_email = MIMEMultipart('mixed')
            full_email[
                'Subject'] = '[' + self.conf['subject_keyword'] + '] ' + title
            full_email['From'] = self.conf['from']
            full_email['To'] = self.conf['to']

            # Create the body of the message (a plain-text and an HTML version).
            body = MIMEMultipart('alternative')
            body.attach(
                MIMEText((short_description + "\n\n" +
                          additional_description).encode('utf-8'),
                         'plain',
                         _charset='utf-8'))
            body.attach(
                MIMEText(("""\
                                    <html>
                                      <head></head>
                                      <body>
                                        <p>""" + short_description +
                          """</p><br>
                                        """ + additional_description + """
                                      </body>
                                    </html>
                                    """).encode('utf-8'),
                         'html',
                         _charset='utf-8'))
            full_email.attach(body)

            # Create the attachment of the message in text/csv.
            attachment = MIMENonMultipart('text', 'csv', charset='utf-8')
            attachment.add_header('Content-Disposition',
                                  'attachment',
                                  filename=report['filename'])
            cs = Charset('utf-8')
            cs.body_encoding = BASE64
            attachment.set_payload(report['content'].encode('utf-8'),
                                   charset=cs)
            full_email.attach(attachment)

            # Send the message via SMTP server.
            s = smtplib.SMTP(self.conf['server'], self.conf['port'])
            if self.conf['tls'] == 'yes':
                s.starttls()
            if not self.conf['login'] == '':
                s.login(self.conf['login'], self.conf['password'])
            # sendmail function takes 3 arguments: sender's address, recipient's address
            # and message to send - here it is sent as one string.
            s.sendmail(self.conf['from'], self.conf['to'],
                       full_email.as_string())
            # self.logger.info('email sent')
            s.quit()
Esempio n. 8
0
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())
Esempio n. 9
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
Esempio n. 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("[,.@()\[\]\\\:;]", 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
Esempio n. 12
0
def emailPlain(
    template, subject=None, toinform=[], context={}, attachments=[], forreal=True
):
    # try to stick to rfc822 (django default is base64) religiously; also
    # as it helps with spam filters.
    cs = Charset("utf-8")
    cs.body_encoding = QP

    # Weed out duplicates.
    to = list(set(flatten(toinform)))

    context["base"] = settings.BASE

    body = render_to_string(template, context)

    if not subject:
        body = body.split("\n")
        subject = body[0].rstrip()
        subject = re.sub("^Subject:\s+", string=subject, repl="", flags=re.IGNORECASE)
        body = "\n".join(body[1:])

    body_html = (
        "<html><head><title>%s</title></head><body><pre>%s</pre></body><html>"
        % (subject, body)
    )

    msg = MIMEMultipart("alternative")

    part1 = MIMEText(body, "plain", _charset=cs)

    part2 = MIMEMultipart("related")
    part2.attach(MIMEText(body_html, "html", _charset=cs))

    email = EmailMessage(
        subject.strip(), None, to=to, from_email=settings.DEFAULT_FROM_EMAIL
    )

    for attachment in attachments:
        part2.attach(attachment)

    msg.attach(part1)
    msg.attach(part2)

    email.attach(msg)
    if forreal:
        email.send()
    else:
        print("To:\t%s\nSubject: %s\n%s\n\n" % (to, subject, body))
Esempio n. 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()
Esempio n. 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()
Esempio n. 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
Esempio n. 16
0
    def init_payload(self):
        super().init_payload()
        self.all_recipients = []
        self.mime_message = self.message.message()

        # Work around an Amazon SES bug where, if all of:
        #   - the message body (text or html) contains non-ASCII characters
        #   - the body is sent with `Content-Transfer-Encoding: 8bit`
        #     (which is Django email's default for most non-ASCII bodies)
        #   - you are using an SES ConfigurationSet with open or click tracking enabled
        # then SES replaces the non-ASCII characters with question marks as it rewrites
        # the message to add tracking. Forcing `CTE: quoted-printable` avoids the problem.
        # (https://forums.aws.amazon.com/thread.jspa?threadID=287048)
        for part in self.mime_message.walk():
            if part.get_content_maintype() == "text" and part["Content-Transfer-Encoding"] == "8bit":
                content = part.get_payload()
                del part["Content-Transfer-Encoding"]
                qp_charset = Charset(part.get_content_charset("us-ascii"))
                qp_charset.body_encoding = QP
                # (can't use part.set_payload, because SafeMIMEText can undo this workaround)
                MIMEText.set_payload(part, content, charset=qp_charset)
Esempio n. 17
0
    def send_mail(self, mail_template, in_reply_to = None, **kwargs):
        msgid = make_msgid()

        subject = mail_template['subject'].format(**kwargs)
        message = mail_template['message'].format(**kwargs)

        msg = MIMEMultipart('alternative')
        msg['Subject'] = str(Header(subject, 'utf-8'))
        msg['From'] = str(Header(SMTP_FROM, 'utf-8'))
        msg['To'] = str(Header(self.email, 'utf-8'))
        msg['Message-ID'] = msgid
        msg['Reply-To'] = SMTP_REPLY_TO_EMAIL
        msg['Date'] = datetime.datetime.now(pytz.utc).strftime("%a, %e %b %Y %T %z")

        if in_reply_to:
            msg['In-Reply-To'] = in_reply_to
            msg['References'] = in_reply_to

        # add message
        charset = Charset('utf-8')
        # QP = quoted printable; this is better readable instead of base64, when
        # the mail is read in plaintext!
        charset.body_encoding = QP
        message_part = MIMEText(message.encode('utf-8'), 'plain', charset)
        msg.attach(message_part)

        if DEBUG:
            with open("/tmp/keepitup_mails.log", "a") as f:
                f.write(msg.as_string() + "\n")
        else:
            with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
                server.ehlo()
                if SMTP_USE_STARTTLS:
                    context = ssl.create_default_context()
                    server.starttls(context=context)

                server.sendmail(SMTP_FROM, self.email, msg.as_string())

        return msgid
Esempio n. 18
0
def build_message(
    subject,
    from_email,
    html,
    to_recipients=[],
    bcc_recipients=[],
    attachments=[],
    headers=[],
):
    """Build raw email for sending."""
    message = MIMEMultipart("alternative")
    cs = Charset("utf-8")
    cs.body_encoding = QP

    message["Subject"] = subject
    message["From"] = from_email

    if to_recipients:
        message["To"] = ",".join(to_recipients)
    if bcc_recipients:
        message["Bcc"] = ",".join(bcc_recipients)

    text = get_text_from_html(html)
    plain_text = MIMEText(text, "plain", cs)
    message.attach(plain_text)

    html_text = MIMEText(html, "html", cs)
    message.attach(html_text)

    for header in headers:
        message[header["key"]] = header["value"]

    for filename in attachments:
        with open(filename, "rb") as attachment:
            part = MIMEApplication(attachment.read())
            part.add_header("Content-Disposition", "attachment", filename="report.pdf")
        message.attach(part)

    return message.as_string()
Esempio n. 19
0
    def sendMailMessage(self, xMailMessage):
        COMMASPACE = ', '

        if dbg:
            print("PyMailSMTPService sendMailMessage", file=dbgout)
        recipients = xMailMessage.getRecipients()
        sendermail = xMailMessage.SenderAddress
        sendername = xMailMessage.SenderName
        subject = xMailMessage.Subject
        ccrecipients = xMailMessage.getCcRecipients()
        bccrecipients = xMailMessage.getBccRecipients()
        if dbg:
            print("PyMailSMTPService subject: " + subject, file=dbgout)
            print("PyMailSMTPService from:  " + sendername, file=dbgout)
            print("PyMailSMTPService from:  " + sendermail, file=dbgout)
            print("PyMailSMTPService send to: %s" % (recipients, ),
                  file=dbgout)

        attachments = xMailMessage.getAttachments()

        textmsg = Message()

        content = xMailMessage.Body
        flavors = content.getTransferDataFlavors()
        if dbg:
            print("PyMailSMTPService flavors len: %d" % (len(flavors), ),
                  file=dbgout)

        #Use first flavor that's sane for an email body
        for flavor in flavors:
            if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find(
                    'text/plain') != -1:
                if dbg:
                    print("PyMailSMTPService mimetype is: " + flavor.MimeType,
                          file=dbgout)
                textbody = content.getTransferData(flavor)

                if len(textbody):
                    mimeEncoding = re.sub("charset=.*", "charset=UTF-8",
                                          flavor.MimeType)
                    if mimeEncoding.find('charset=UTF-8') == -1:
                        mimeEncoding = mimeEncoding + "; charset=UTF-8"
                    textmsg['Content-Type'] = mimeEncoding
                    textmsg['MIME-Version'] = '1.0'

                    try:
                        #it's a string, get it as utf-8 bytes
                        textbody = textbody.encode('utf-8')
                    except:
                        #it's a bytesequence, get raw bytes
                        textbody = textbody.value
                    textbody = textbody.decode('utf-8')
                    c = Charset('utf-8')
                    c.body_encoding = QP
                    textmsg.set_payload(textbody, c)

                break

        if (len(attachments)):
            msg = MIMEMultipart()
            msg.epilogue = ''
            msg.attach(textmsg)
        else:
            msg = textmsg

        hdr = Header(sendername, 'utf-8')
        hdr.append('<' + sendermail + '>', 'us-ascii')
        msg['Subject'] = subject
        msg['From'] = hdr
        msg['To'] = COMMASPACE.join(recipients)
        if len(ccrecipients):
            msg['Cc'] = COMMASPACE.join(ccrecipients)
        if xMailMessage.ReplyToAddress != '':
            msg['Reply-To'] = xMailMessage.ReplyToAddress

        mailerstring = "LibreOffice via Caolan's mailmerge component"
        try:
            ctx = uno.getComponentContext()
            aConfigProvider = ctx.ServiceManager.createInstance(
                "com.sun.star.configuration.ConfigurationProvider")
            prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
            prop.Name = "nodepath"
            prop.Value = "/org.openoffice.Setup/Product"
            aSettings = aConfigProvider.createInstanceWithArguments(
                "com.sun.star.configuration.ConfigurationAccess", (prop, ))
            mailerstring = aSettings.getByName("ooName") + " " + \
             aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component"
        except:
            pass

        msg['X-Mailer'] = mailerstring
        msg['Date'] = formatdate(localtime=True)

        for attachment in attachments:
            content = attachment.Data
            flavors = content.getTransferDataFlavors()
            flavor = flavors[0]
            ctype = flavor.MimeType
            maintype, subtype = ctype.split('/', 1)
            msgattachment = MIMEBase(maintype, subtype)
            data = content.getTransferData(flavor)
            msgattachment.set_payload(data.value)
            encode_base64(msgattachment)
            fname = attachment.ReadableName
            try:
                msgattachment.add_header('Content-Disposition', 'attachment', \
                 filename=fname)
            except:
                msgattachment.add_header('Content-Disposition', 'attachment', \
                 filename=('utf-8','',fname))
            if dbg:
                print(("PyMailSMTPService attachmentheader: ",
                       str(msgattachment)),
                      file=dbgout)

            msg.attach(msgattachment)

        uniquer = {}
        for key in recipients:
            uniquer[key] = True
        if len(ccrecipients):
            for key in ccrecipients:
                uniquer[key] = True
        if len(bccrecipients):
            for key in bccrecipients:
                uniquer[key] = True
        truerecipients = uniquer.keys()

        if dbg:
            print(("PyMailSMTPService recipients are: ", truerecipients),
                  file=dbgout)

        self.server.sendmail(sendermail, truerecipients, msg.as_string())
Esempio n. 20
0
def _getMessage(ctx, message):
    COMMASPACE = ', '
    sendermail = message.SenderAddress
    sendername = message.SenderName
    subject = message.Subject
    if isDebugMode():
        msg = getMessage(ctx, g_message, 251, subject)
        logMessage(ctx, INFO, msg, 'SmtpService', 'sendMailMessage()')
    textmsg = Message()
    content = message.Body
    flavors = content.getTransferDataFlavors()
    #Use first flavor that's sane for an email body
    for flavor in flavors:
        if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find(
                'text/plain') != -1:
            textbody = content.getTransferData(flavor)
            if len(textbody):
                mimeEncoding = re.sub('charset=.*', 'charset=UTF-8',
                                      flavor.MimeType)
                if mimeEncoding.find('charset=UTF-8') == -1:
                    mimeEncoding = mimeEncoding + '; charset=UTF-8'
                textmsg['Content-Type'] = mimeEncoding
                textmsg['MIME-Version'] = '1.0'
                try:
                    #it's a string, get it as utf-8 bytes
                    textbody = textbody.encode('utf-8')
                except:
                    #it's a bytesequence, get raw bytes
                    textbody = textbody.value
                if sys.version >= '3':
                    if sys.version_info.minor < 3 or (
                            sys.version_info.minor == 3
                            and sys.version_info.micro <= 1):
                        #http://stackoverflow.com/questions/9403265/how-do-i-use-python-3-2-email-module-to-send-unicode-messages-encoded-in-utf-8-w
                        #see http://bugs.python.org/16564, etc. basically it now *seems* to be all ok
                        #in python 3.3.2 onwards, but a little busted in 3.3.0
                        textbody = textbody.decode('iso8859-1')
                    else:
                        textbody = textbody.decode('utf-8')
                    c = Charset('utf-8')
                    c.body_encoding = QP
                    textmsg.set_payload(textbody, c)
                else:
                    textmsg.set_payload(textbody)
            break
    if message.hasAttachments():
        msg = MIMEMultipart()
        msg.epilogue = ''
        msg.attach(textmsg)
    else:
        msg = textmsg
    header = Header(sendername, 'utf-8')
    header.append('<' + sendermail + '>', 'us-ascii')
    msg['Subject'] = subject
    msg['From'] = header
    msg['To'] = COMMASPACE.join(message.getRecipients())
    msg['Message-ID'] = message.MessageId
    if message.ThreadId:
        msg['References'] = message.ThreadId
    if message.hasCcRecipients():
        msg['Cc'] = COMMASPACE.join(message.getCcRecipients())
    if message.ReplyToAddress != '':
        msg['Reply-To'] = message.ReplyToAddress
    xmailer = "LibreOffice / OpenOffice via smtpMailerOOo extention"
    try:
        configuration = getConfiguration(ctx, '/org.openoffice.Setup/Product')
        name = configuration.getByName('ooName')
        version = configuration.getByName('ooSetupVersion')
        xmailer = "%s %s via smtpMailerOOo extention" % (name, version)
    except:
        pass
    msg['X-Mailer'] = xmailer
    msg['Date'] = formatdate(localtime=True)
    for attachment in message.getAttachments():
        content = attachment.Data
        flavors = content.getTransferDataFlavors()
        flavor = flavors[0]
        ctype = flavor.MimeType
        maintype, subtype = ctype.split('/', 1)
        msgattachment = MIMEBase(maintype, subtype)
        data = content.getTransferData(flavor)
        msgattachment.set_payload(data.value)
        encode_base64(msgattachment)
        fname = attachment.ReadableName
        try:
            msgattachment.add_header('Content-Disposition', 'attachment', \
                filename=fname)
        except:
            msgattachment.add_header('Content-Disposition', 'attachment', \
                filename=('utf-8','',fname))
        msg.attach(msgattachment)
    return msg
Esempio n. 21
0
    def send(self):
        """Perform all send operations related to this email...

        These consists in:
            - send the notification email;
            - call self.filer_cmd if not None.

        REMARKS
            If the GIT_HOOKS_TESTSUITE_MODE environment variable
            is set, then a trace of the email is printed, instead
            of sending it.  This is for testing purposes.
        """
        # Force the charset being used to UTF-8. We could possibly try
        # to guess whether more primitive charsets might work such as
        # ASCII or IS0-8859-15, but UTF-8 is so close to those encodings
        # that it is not worth the extra complication.
        #
        # The one situation where it might be worth guessing the charset
        # is when the email body contains some characters which are not
        # available in UTF-8. Since UTF-8 is so widely used, we'll assume
        # for now that it's not necessary in practice to support this
        # scenario.
        e_msg_charset = Charset("UTF-8")

        # Force quoted-printable encoding for our emails.
        #
        # Using this encoding helps ensure that the email payload
        # does not exceed any of the limitations that SMTP servers
        # might have. In particular, while RFC 6152 now defines
        # the "8bit" Content-Transfer-Encoding as being a legal
        # extension, it also warns us of some limitations:
        #
        #        | Note that this extension does NOT eliminate
        #        | the possibility of an SMTP server limiting line
        #        | length; servers are free to implement this extension
        #        | but nevertheless set a line length limit no lower
        #        | than 1000 octets.
        #
        # We also prefer the quoted-printable encoding over the base64
        # one because:
        #
        #    - The output that's generally easier for humans to read';
        #    - The output is also usually smaller in size for typical
        #      text.
        e_msg_charset.body_encoding = QP

        e_msg_body = self.__email_body_with_diff

        # Handle the situation where we were manually called by a user
        # (as opposed by Git itself) who would like us to re-send the emails,
        # with a warning banner indicating that the emails were re-generated.
        # The banner is added at the beginning of the email body.
        #
        # The main reason for adding the banner is that it helps prevent users
        # from thinking the commit was pushed at the time the email was sent.
        #
        # Note that the option of allowing the user to use the banner
        # of his choice was considered. In the end, we decided against it
        # for now, because we wanted it to be very simple for the user
        # to trigger the addition of the banner during the re-send,
        # while at the same time keeping the code in the git-hooks
        # as simple as possible also (i.e. we avoided the introduction
        # of multiple environment variables, for instance).

        manual_replay_reason = os.environ.get("GIT_HOOKS_EMAIL_REPLAY_REASON")
        if manual_replay_reason is not None:
            warning_banner = EMAIL_REPLAY_WARNING_BANNER.format(
                reason=manual_replay_reason)
            e_msg_body = warning_banner + "\n" + e_msg_body

        e_msg = MIMEText(e_msg_body, _charset=e_msg_charset)

        # Create the email's header.
        e_msg["From"] = sanitized_email_address(self.email_info.email_from)
        e_msg["To"] = ", ".join(map(sanitized_email_address, self.email_to))
        if self.email_bcc:
            e_msg["Bcc"] = ", ".join(
                map(sanitized_email_address, self.email_bcc))
        e_msg["Subject"] = sanitized_email_header_field(self.email_subject)
        e_msg["X-Act-Checkin"] = self.email_info.project_name
        e_msg["X-Git-Author"] = sanitized_email_address(
            self.author or self.email_info.email_from)
        e_msg["X-Git-Refname"] = self.ref_name
        e_msg["X-Git-Oldrev"] = self.old_rev
        e_msg["X-Git-Newrev"] = self.new_rev

        # email_from = e_msg.get('From')
        email_recipients = [
            addr[1] for addr in getaddresses(
                e_msg.get_all("To", []) + e_msg.get_all("Cc", []) +
                e_msg.get_all("Bcc", []))
        ]

        sendmail(
            self.email_info.email_from,
            email_recipients,
            e_msg.as_string(),
            "localhost",
        )

        if self.filer_cmd is not None:
            self.__call_filer_cmd()
Esempio n. 22
0
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
# Email: [email protected]; WWW: http://www.mysociety.org/
#
# $Id: sendemail.py,v 1.5 2009/12/17 17:31:04 francis dead $
#

import re, smtplib
from minimock import mock, Mock
from email.message import Message
from email.header import Header
from email.utils import formataddr, make_msgid, formatdate
from email.charset import Charset, QP

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


def send_email(sender, to, message, headers={}):
    """Sends MESSAGE from SENDER to TO, with HEADERS
    Returns True if successful, False if not
    
    >>> mock('smtplib.SMTP', returns=Mock('smtp_connection'))
    >>> send_email("[email protected]", "[email protected]", "Hello, this is a message!", {
    ...     'Subject': 'Mapumental message',
    ...     'From': ("[email protected]", "Ms. A"),
    ...     'To': "[email protected]"
    ... }) # doctest:+ELLIPSIS
    Called smtplib.SMTP('localhost')
    Called smtp_connection.sendmail(
        '[email protected]',
Esempio n. 23
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
Esempio n. 24
0
    def sendMailMessage(self, xMailMessage):
        COMMASPACE = ', '

        if dbg:
            print("PyMailSMTPService sendMailMessage", file=dbgout)
        recipients = xMailMessage.getRecipients()
        sendermail = xMailMessage.SenderAddress
        sendername = xMailMessage.SenderName
        subject = xMailMessage.Subject
        ccrecipients = xMailMessage.getCcRecipients()
        bccrecipients = xMailMessage.getBccRecipients()
        if dbg:
            print("PyMailSMTPService subject: " + subject, file=dbgout)
            print("PyMailSMTPService from:  " + sendername, file=dbgout)
            print("PyMailSMTPService from:  " + sendermail, file=dbgout)
            print("PyMailSMTPService send to: %s" % (recipients, ),
                  file=dbgout)

        attachments = xMailMessage.getAttachments()

        textmsg = Message()

        content = xMailMessage.Body
        flavors = content.getTransferDataFlavors()
        if dbg:
            print("PyMailSMTPService flavors len: %d" % (len(flavors), ),
                  file=dbgout)

        #Use first flavor that's sane for an email body
        for flavor in flavors:
            if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find(
                    'text/plain') != -1:
                if dbg:
                    print("PyMailSMTPService mimetype is: " + flavor.MimeType,
                          file=dbgout)
                textbody = content.getTransferData(flavor)

                if len(textbody):
                    mimeEncoding = re.sub("charset=.*", "charset=UTF-8",
                                          flavor.MimeType)
                    if mimeEncoding.find('charset=UTF-8') == -1:
                        mimeEncoding = mimeEncoding + "; charset=UTF-8"
                    textmsg['Content-Type'] = mimeEncoding
                    textmsg['MIME-Version'] = '1.0'

                    try:
                        #it's a string, get it as utf-8 bytes
                        textbody = textbody.encode('utf-8')
                    except:
                        #it's a bytesequence, get raw bytes
                        textbody = textbody.value
                    if sys.version >= '3':
                        if sys.version_info.minor < 3 or (
                                sys.version_info.minor == 3
                                and sys.version_info.micro <= 1):
                            #http://stackoverflow.com/questions/9403265/how-do-i-use-python-3-2-email-module-to-send-unicode-messages-encoded-in-utf-8-w
                            #see http://bugs.python.org/16564, etc. basically it now *seems* to be all ok
                            #in python 3.3.2 onwards, but a little busted in 3.3.0

                            textbody = textbody.decode('iso8859-1')
                        else:
                            textbody = textbody.decode('utf-8')
                        c = Charset('utf-8')
                        c.body_encoding = QP
                        textmsg.set_payload(textbody, c)
                    else:
                        textmsg.set_payload(textbody)

                break

        if (len(attachments)):
            msg = MIMEMultipart()
            msg.epilogue = ''
            msg.attach(textmsg)
        else:
            msg = textmsg

        hdr = Header(sendername, 'utf-8')
        hdr.append('<' + sendermail + '>', 'us-ascii')
        msg['Subject'] = subject
        msg['From'] = hdr
        msg['To'] = COMMASPACE.join(recipients)
        if len(ccrecipients):
            msg['Cc'] = COMMASPACE.join(ccrecipients)
        if xMailMessage.ReplyToAddress != '':
            msg['Reply-To'] = xMailMessage.ReplyToAddress

        mailerstring = "LibreOffice via Caolan's mailmerge component"
        try:
            configuration = self._getConfiguration(
                "/org.openoffice.Setup/Product")
            mailerstring = "%s %s via Caolan's mailmerge component" % (
                configuration.getByName("ooName"),
                configuration.getByName("ooSetupVersion"))
        except:
            pass

        msg['X-Mailer'] = mailerstring
        msg['Date'] = formatdate(localtime=True)

        for attachment in attachments:
            content = attachment.Data
            flavors = content.getTransferDataFlavors()
            flavor = flavors[0]
            ctype = flavor.MimeType
            maintype, subtype = ctype.split('/', 1)
            msgattachment = MIMEBase(maintype, subtype)
            data = content.getTransferData(flavor)
            msgattachment.set_payload(data.value)
            encode_base64(msgattachment)
            fname = attachment.ReadableName
            try:
                msgattachment.add_header('Content-Disposition', 'attachment', \
                    filename=fname)
            except:
                msgattachment.add_header('Content-Disposition', 'attachment', \
                    filename=('utf-8','',fname))
            if dbg:
                print(("PyMailSMTPService attachmentheader: ",
                       str(msgattachment)),
                      file=dbgout)

            msg.attach(msgattachment)

        uniquer = {}
        for key in recipients:
            uniquer[key] = True
        if len(ccrecipients):
            for key in ccrecipients:
                uniquer[key] = True
        if len(bccrecipients):
            for key in bccrecipients:
                uniquer[key] = True
        truerecipients = uniquer.keys()

        if dbg:
            print(("PyMailSMTPService recipients are: ", truerecipients),
                  file=dbgout)

        self.server.sendmail(sendermail, truerecipients, msg.as_string())
Esempio n. 25
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))
Esempio n. 26
0
    def send_email(self, recipients, cc, subject, content, report):
        """Sends an email with attachment.
        Refer to https://gist.github.com/BietteMaxime/f75ae41f7b4557274a9f

        Args:
            recipients: To whom to send the email.
            cc: To whom to cc the email.
            subject: Email subject.
            content: Email body content
            report: A dictionary containing "filename", "data" to construct a
                CSV attachment.

        Returns:
            None
        """
        # Get sender from configuration
        sender = self.smtp["smtp_from"]

        # Create message container - the correct MIME type is multipart/mixed
        # to allow attachment.
        full_email = MIMEMultipart("mixed")
        full_email["Subject"] = subject
        full_email["From"] = sender
        full_email["To"] = ", ".join(recipients)
        full_email["CC"] = ", ".join(cc)

        # Create the body of the message (a plain-text version).
        content = content.encode(ENCODING)
        content = MIMEText(content, "plain", _charset=ENCODING)
        body = MIMEMultipart("alternative")
        body.attach(content)
        full_email.attach(body)

        # Create the attachment of the message in text/csv.
        attachment = MIMENonMultipart("text", "csv", charset=ENCODING)
        attachment.add_header("Content-Disposition",
                              "attachment",
                              filename=report["filename"])
        cs = Charset(ENCODING)
        cs.body_encoding = BASE64
        attachment.set_payload(report["data"].encode(ENCODING), charset=cs)
        full_email.attach(attachment)

        try:
            with smtplib.SMTP(self.smtp["smtp_url"]) as server:
                server.starttls()

                username = self.smtp["smtp_auth_username"]
                password = self.smtp["smtp_auth_password"]
                server.login(username, password)

                receivers = recipients + cc
                server.sendmail(sender, receivers, full_email.as_string())
                self.logger.info("Successfully sent email to %s and cc %s",
                                 ", ".join(recipients), ", ".join(cc))
        except smtplib.SMTPAuthenticationError:
            self.logger.warning("The server didn\'t accept the user\\password "
                                "combination.")
        except smtplib.SMTPServerDisconnected:
            self.logger.warning("Server unexpectedly disconnected")
        except smtplib.SMTPException as e:
            self.logger.exception("SMTP error occurred: %s", e)
Esempio n. 27
0
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
# Email: [email protected]; WWW: http://www.mysociety.org/
#
# $Id: sendemail.py,v 1.5 2009/12/17 17:31:04 francis dead $
#

import re, smtplib
from minimock import mock, Mock
from email.message import Message
from email.header import Header
from email.utils import formataddr, make_msgid, formatdate
from email.charset import Charset, QP

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

def send_email(sender, to, message, headers={}):
    """Sends MESSAGE from SENDER to TO, with HEADERS
    Returns True if successful, False if not
    
    >>> mock('smtplib.SMTP', returns=Mock('smtp_connection'))
    >>> send_email("[email protected]", "[email protected]", "Hello, this is a message!", {
    ...     'Subject': 'Mapumental message',
    ...     'From': ("[email protected]", "Ms. A"),
    ...     'To': "[email protected]"
    ... }) # doctest:+ELLIPSIS
    Called smtplib.SMTP('localhost')
    Called smtp_connection.sendmail(
        '[email protected]',
        '[email protected]',
Esempio n. 28
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()
Esempio n. 29
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()
Esempio n. 30
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")
Esempio n. 31
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")
Esempio n. 32
0
    def __init__(self, payload, charset='utf-8'):
        MIMENonMultipart.__init__(self, 'text', 'plain', charset=charset)

        utf8qp = Charset(charset)
        utf8qp.body_encoding = QP
        self.set_payload(payload, charset=utf8qp)
Esempio n. 33
0
	def sendMailMessage(self, xMailMessage):
		COMMASPACE = ', '

		if dbg:
			print("PyMailSMTPService sendMailMessage", file=dbgout)
		recipients = xMailMessage.getRecipients()
		sendermail = xMailMessage.SenderAddress
		sendername = xMailMessage.SenderName
		subject = xMailMessage.Subject
		ccrecipients = xMailMessage.getCcRecipients()
		bccrecipients = xMailMessage.getBccRecipients()
		if dbg:
			print("PyMailSMTPService subject: " + subject, file=dbgout)
			print("PyMailSMTPService from:  " + sendername, file=dbgout)
			print("PyMailSMTPService from:  " + sendermail, file=dbgout)
			print("PyMailSMTPService send to: %s" % (recipients,), file=dbgout)

		attachments = xMailMessage.getAttachments()

		textmsg = Message()

		content = xMailMessage.Body
		flavors = content.getTransferDataFlavors()
		if dbg:
			print("PyMailSMTPService flavors len: %d" % (len(flavors),), file=dbgout)

		#Use first flavor that's sane for an email body
		for flavor in flavors:
			if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find('text/plain') != -1:
				if dbg:
					print("PyMailSMTPService mimetype is: " + flavor.MimeType, file=dbgout)
				textbody = content.getTransferData(flavor)

				if len(textbody):
					mimeEncoding = re.sub("charset=.*", "charset=UTF-8", flavor.MimeType)
					if mimeEncoding.find('charset=UTF-8') == -1:
						mimeEncoding = mimeEncoding + "; charset=UTF-8"
					textmsg['Content-Type'] = mimeEncoding
					textmsg['MIME-Version'] = '1.0'

					try:
						#it's a string, get it as utf-8 bytes
						textbody = textbody.encode('utf-8')
					except:
						#it's a bytesequence, get raw bytes
						textbody = textbody.value
					if sys.version >= '3':
						if sys.version_info.minor < 3 or (sys.version_info.minor == 3 and sys.version_info.micro <= 1):
							#http://stackoverflow.com/questions/9403265/how-do-i-use-python-3-2-email-module-to-send-unicode-messages-encoded-in-utf-8-w
							#see http://bugs.python.org/16564, etc. basically it now *seems* to be all ok
							#in python 3.3.2 onwards, but a little busted in 3.3.0

							textbody = textbody.decode('iso8859-1')
						else:
							textbody = textbody.decode('utf-8')
						c = Charset('utf-8')
						c.body_encoding = QP
						textmsg.set_payload(textbody, c)
					else:
						textmsg.set_payload(textbody)

				break

		if (len(attachments)):
			msg = MIMEMultipart()
			msg.epilogue = ''
			msg.attach(textmsg)
		else:
			msg = textmsg

		hdr = Header(sendername, 'utf-8')
		hdr.append('<'+sendermail+'>','us-ascii')
		msg['Subject'] = subject
		msg['From'] = hdr
		msg['To'] = COMMASPACE.join(recipients)
		if len(ccrecipients):
			msg['Cc'] = COMMASPACE.join(ccrecipients)
		if xMailMessage.ReplyToAddress != '':
			msg['Reply-To'] = xMailMessage.ReplyToAddress

		mailerstring = "LibreOffice via Caolan's mailmerge component"
		try:
			ctx = uno.getComponentContext()
			aConfigProvider = ctx.ServiceManager.createInstance("com.sun.star.configuration.ConfigurationProvider")
			prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
			prop.Name = "nodepath"
			prop.Value = "/org.openoffice.Setup/Product"
			aSettings = aConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess",
				(prop,))
			mailerstring = aSettings.getByName("ooName") + " " + \
				aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component"
		except:
			pass

		msg['X-Mailer'] = mailerstring
		msg['Date'] = formatdate(localtime=True)

		for attachment in attachments:
			content = attachment.Data
			flavors = content.getTransferDataFlavors()
			flavor = flavors[0]
			ctype = flavor.MimeType
			maintype, subtype = ctype.split('/', 1)
			msgattachment = MIMEBase(maintype, subtype)
			data = content.getTransferData(flavor)
			msgattachment.set_payload(data.value)
			encode_base64(msgattachment)
			fname = attachment.ReadableName
			try:
				msgattachment.add_header('Content-Disposition', 'attachment', \
					filename=fname)
			except:
				msgattachment.add_header('Content-Disposition', 'attachment', \
					filename=('utf-8','',fname))
			if dbg:
				print(("PyMailSMTPService attachmentheader: ", str(msgattachment)), file=dbgout)

			msg.attach(msgattachment)

		uniquer = {}
		for key in recipients:
			uniquer[key] = True
		if len(ccrecipients):
			for key in ccrecipients:
				uniquer[key] = True
		if len(bccrecipients):
			for key in bccrecipients:
				uniquer[key] = True
		truerecipients = uniquer.keys()

		if dbg:
			print(("PyMailSMTPService recipients are: ", truerecipients), file=dbgout)

		self.server.sendmail(sendermail, truerecipients, msg.as_string())
Esempio n. 34
0
 def sendMailMessage(self, message):
     COMMASPACE = ', '
     recipients = message.getRecipients()
     sendermail = message.SenderAddress
     sendername = message.SenderName
     subject = message.Subject
     if isDebugMode():
         msg = getMessage(self._ctx, g_message, 161, subject)
         logMessage(self._ctx, INFO, msg, 'SmtpService',
                    'sendMailMessage()')
     ccrecipients = message.getCcRecipients()
     bccrecipients = message.getBccRecipients()
     attachments = message.getAttachments()
     textmsg = Message()
     content = message.Body
     flavors = content.getTransferDataFlavors()
     #Use first flavor that's sane for an email body
     for flavor in flavors:
         if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find(
                 'text/plain') != -1:
             textbody = content.getTransferData(flavor)
             if len(textbody):
                 mimeEncoding = re.sub('charset=.*', 'charset=UTF-8',
                                       flavor.MimeType)
                 if mimeEncoding.find('charset=UTF-8') == -1:
                     mimeEncoding = mimeEncoding + '; charset=UTF-8'
                 textmsg['Content-Type'] = mimeEncoding
                 textmsg['MIME-Version'] = '1.0'
                 try:
                     #it's a string, get it as utf-8 bytes
                     textbody = textbody.encode('utf-8')
                 except:
                     #it's a bytesequence, get raw bytes
                     textbody = textbody.value
                 if sys.version >= '3':
                     if sys.version_info.minor < 3 or (
                             sys.version_info.minor == 3
                             and sys.version_info.micro <= 1):
                         #http://stackoverflow.com/questions/9403265/how-do-i-use-python-3-2-email-module-to-send-unicode-messages-encoded-in-utf-8-w
                         #see http://bugs.python.org/16564, etc. basically it now *seems* to be all ok
                         #in python 3.3.2 onwards, but a little busted in 3.3.0
                         textbody = textbody.decode('iso8859-1')
                     else:
                         textbody = textbody.decode('utf-8')
                     c = Charset('utf-8')
                     c.body_encoding = QP
                     textmsg.set_payload(textbody, c)
                 else:
                     textmsg.set_payload(textbody)
             break
     if len(attachments):
         msg = MIMEMultipart()
         msg.epilogue = ''
         msg.attach(textmsg)
     else:
         msg = textmsg
     header = Header(sendername, 'utf-8')
     header.append('<' + sendermail + '>', 'us-ascii')
     msg['Subject'] = subject
     msg['From'] = header
     msg['To'] = COMMASPACE.join(recipients)
     if len(ccrecipients):
         msg['Cc'] = COMMASPACE.join(ccrecipients)
     if message.ReplyToAddress != '':
         msg['Reply-To'] = message.ReplyToAddress
     mailerstring = "LibreOffice via smtpMailerOOo component"
     try:
         configuration = getConfiguration(self._ctx,
                                          '/org.openoffice.Setup/Product')
         name = configuration.getByName('ooName')
         version = configuration.getByName('ooSetupVersion')
         mailerstring = "%s %s via via smtpMailerOOo component" % (name,
                                                                   version)
     except:
         pass
     msg['X-Mailer'] = mailerstring
     msg['Date'] = formatdate(localtime=True)
     for attachment in attachments:
         content = attachment.Data
         flavors = content.getTransferDataFlavors()
         flavor = flavors[0]
         ctype = flavor.MimeType
         maintype, subtype = ctype.split('/', 1)
         msgattachment = MIMEBase(maintype, subtype)
         data = content.getTransferData(flavor)
         msgattachment.set_payload(data.value)
         encode_base64(msgattachment)
         fname = attachment.ReadableName
         try:
             msgattachment.add_header('Content-Disposition', 'attachment', \
                 filename=fname)
         except:
             msgattachment.add_header('Content-Disposition', 'attachment', \
                 filename=('utf-8','',fname))
         msg.attach(msgattachment)
     uniquer = {}
     for key in recipients:
         uniquer[key] = True
     if len(ccrecipients):
         for key in ccrecipients:
             uniquer[key] = True
     if len(bccrecipients):
         for key in bccrecipients:
             uniquer[key] = True
     truerecipients = uniquer.keys()
     error = None
     try:
         refused = self._server.sendmail(sendermail, truerecipients,
                                         msg.as_string())
     except smtplib.SMTPSenderRefused as e:
         msg = getMessage(self._ctx, g_message, 162,
                          (subject, getExceptionMessage(e)))
         error = MailException(msg, self)
     except smtplib.SMTPRecipientsRefused as e:
         msg = getMessage(self._ctx, g_message, 163,
                          (subject, getExceptionMessage(e)))
         # TODO: return SendMailMessageFailedException in place of MailException
         # TODO: error = SendMailMessageFailedException(msg, self)
         error = MailException(msg, self)
     except smtplib.SMTPDataError as e:
         msg = getMessage(self._ctx, g_message, 163,
                          (subject, getExceptionMessage(e)))
         error = MailException(msg, self)
     except Exception as e:
         msg = getMessage(self._ctx, g_message, 163,
                          (subject, getExceptionMessage(e)))
         error = MailException(msg, self)
     else:
         if len(refused) > 0:
             for address, result in refused.items():
                 code, reply = getReply(*result)
                 msg = getMessage(self._ctx, g_message, 164,
                                  (subject, address, code, reply))
                 logMessage(self._ctx, SEVERE, msg, 'SmtpService',
                            'sendMailMessage()')
         elif isDebugMode():
             msg = getMessage(self._ctx, g_message, 165, subject)
             logMessage(self._ctx, INFO, msg, 'SmtpService',
                        'sendMailMessage()')
     if error is not None:
         logMessage(self._ctx, SEVERE, error.Message, 'SmtpService',
                    'sendMailMessage()')
         raise error
Esempio n. 35
0
def send_email(smtp, recipients, cc, subject, content, csv_reports):
    """Sends an email with attachment.
    Refer to https://gist.github.com/BietteMaxime/f75ae41f7b4557274a9f

    Args:
        smtp: A dictionary containing smtp info:
            - smtp_url
            - smtp_auth_username # optional
            - smtp_auth_password # optional
            - smtp_from
        recipients: To whom to send the email.
        cc: To whom to cc the email.
        subject: Email subject.
        content: Email body content
        csv_reports: List of dictionaries containing "filename", "data" to
            construct CSV attachments.

    Returns:
        None
    """
    if not isinstance(smtp, dict):
        logger.warning("smtp is not a dictionary. Skip.")
        return

    sender = smtp.get("smtp_from", None)
    smtp_url = smtp.get("smtp_url", None)
    smtp_auth_username = smtp.get("smtp_auth_username", None)
    smtp_auth_password = smtp.get("smtp_auth_password", None)
    if sender is None or smtp_url is None:
        logger.warning("Some fields in smtp %s is None. Skip.", smtp)
        return

    # Create message container - the correct MIME type is multipart/mixed
    # to allow attachment.
    full_email = MIMEMultipart("mixed")
    full_email["Subject"] = subject
    full_email["From"] = sender
    full_email["To"] = ", ".join(recipients)
    full_email["CC"] = ", ".join(cc)

    # Create the body of the message (a plain-text version).
    content = content.encode(ENCODING)
    content = MIMEText(content, "plain", _charset=ENCODING)
    full_email.attach(content)

    # Create the attachment of the message in text/csv.
    for report in csv_reports:
        attachment = MIMENonMultipart("text", "csv", charset=ENCODING)
        attachment.add_header("Content-Disposition",
                              "attachment",
                              filename=report["filename"])
        cs = Charset(ENCODING)
        cs.body_encoding = BASE64
        attachment.set_payload(report["data"].encode(ENCODING), charset=cs)
        full_email.attach(attachment)

    try:
        with smtplib.SMTP(smtp_url) as server:
            if smtp_auth_username is not None and smtp_auth_password is not None:
                server.starttls()
                server.login(smtp_auth_username, smtp_auth_password)

            receivers = recipients + cc
            server.sendmail(sender, receivers, full_email.as_string())
            logger.info("Successfully sent email to %s and cc %s",
                        ", ".join(recipients), ", ".join(cc))
    except smtplib.SMTPAuthenticationError:
        logger.warning("The server didn\'t accept the user\\password "
                       "combination.")
    except smtplib.SMTPServerDisconnected:
        logger.warning("Server unexpectedly disconnected")
    except smtplib.SMTPException as e:
        logger.exception("SMTP error occurred: %s", e)
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)