Ejemplo n.º 1
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()
Ejemplo n.º 2
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()