def mimemelding(self): m = MIMEMultipart() m['Subject'] = Header(self.tittel, self.charset) n = self.ordre.firma.firmanavn.replace(';', ' ').replace(',',' ') m['From'] = '"%s" <%s>' % (Header(n, self.charset), self.fra) #m['To'] = '"%s" <%s>' % (Header(self.ordre.kunde.navn, self.charset), self.til) m['To'] = self.til #'"%s" <%s>' % (Header(self.ordre.kunde.navn, self.charset), self.til) m.preamble = 'You will not see this in a MIME-aware mail reader.\n' # To guarantee the message ends with a newline m.epilogue = '' # Legg til tekstlig informasjon t = MIMEText(self.tekst.encode(self.charset), 'plain', self.charset) m.attach(t) # Legg til fakturaen b = MIMEBase('application', 'x-pdf') _filename=Header('%s-%i.pdf' % (self.ordre.firma.firmanavn, self.ordre.ID), self.charset) b.add_header('Content-Disposition', 'attachment', filename=_filename.encode()) # legg til filnavn m.attach(b) fp = open(self.pdfFilnavn, 'rb') b.set_payload(fp.read()) # les inn fakturaen fp.close() encoders.encode_base64(b) #base64 encode subpart # Legg til vedlegg for filnavn, vedlegg in self.vedlegg: v = MIMEBase('application', 'octet-stream') _filename=Header(filnavn, self.charset) v.add_header('Content-Disposition', 'attachment', filename=_filename.encode()) # legg til filnavn m.attach(v) v.set_payload(vedlegg) encoders.encode_base64(v) #base64 encode subpart return m
def test_japanese_codecs(self): eq = self.ndiffAssertEqual j = Charset("euc-jp") g = Charset("iso-8859-1") h = Header("Hello World!") jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa' ghello = 'Gr\xfc\xdf Gott!' h.append(jhello, j) h.append(ghello, g) # BAW: This used to -- and maybe should -- fold the two iso-8859-1 # chunks into a single encoded word. However it doesn't violate the # standard to have them as two encoded chunks and maybe it's # reasonable <wink> for each .append() call to result in a separate # encoded word. eq(h.encode(), """\ Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?= =?iso-8859-1?q?Gr=FC=DF?= =?iso-8859-1?q?_Gott!?=""") eq(decode_header(h.encode()), [('Hello World!', None), ('\x1b$B%O%m!<%o!<%k%I!*\x1b(B', 'iso-2022-jp'), ('Gr\xfc\xdf Gott!', 'iso-8859-1')]) long = 'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9' h = Header(long, j, header_name="Subject") # test a very long header enc = h.encode() # TK: splitting point may differ by codec design and/or Header encoding eq(enc , """\ =?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?= =?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=""") # TK: full decode comparison eq(h.__unicode__().encode('euc-jp'), long)
def format_str(s): # encode if contain utf-8 or else cannot be correctly dispalyed name,addr = parseaddr(s) print 'name:',name,'addr:',addr head = Header(name,'utf-8') print 'head:',head,'encode:',head.encode() print 'addr encode:',addr.encode() return formataddr((head.encode(),addr.encode()))
def encode_header(key, value): """ encodes a unicode string as a valid header value :param key: the header field this value will be stored in :type key: str :param value: the value to be encoded :type value: unicode """ # handle list of "realname <email>" entries separately if key.lower() in ['from', 'to', 'cc', 'bcc']: rawentries = value.split(',') encodedentries = [] for entry in rawentries: m = re.search('\s*(.*)\s+<(.*\@.*\.\w*)>\s*$', entry) if m: # If a realname part is contained name, address = m.groups() # try to encode as ascii, if that fails, revert to utf-8 # name must be a unicode string here namepart = Header(name) # append address part encoded as ascii entry = '%s <%s>' % (namepart.encode(), address) encodedentries.append(entry) value = Header(', '.join(encodedentries)) else: value = Header(value) return value
def to_mail(to_name, to_email, subject, body, headers={}, decorate_body=True, email_from=None, name_from=None): try: if email_from is None: email_from = config.get('adhocracy.email.from') if name_from is None: name_from = config.get('adhocracy.site.name') if decorate_body: body = (_(u"Hi %s,") % to_name + u"\r\n\r\n%s\r\n\r\n" % body + _(u"Cheers,\r\n\r\n" u" the %s Team\r\n") % config.get('adhocracy.site.name')) msg = MIMEText(body.encode(ENCODING), 'plain', ENCODING) for k, v in headers.items(): msg[k] = v subject = Header(subject.encode(ENCODING), ENCODING) msg['Subject'] = subject msg['From'] = _("%s <%s>") % (name_from, email_from) to = Header(u"%s <%s>" % (to_name, to_email), ENCODING) msg['To'] = to msg['Date'] = email.Utils.formatdate(time()) msg['X-Mailer'] = "Adhocracy SMTP %s" % version.get_version() #log.debug("MAIL\r\n" + msg.as_string()) send(email_from, to_email, msg.as_string()) except Exception: log.exception("Sending mail failed.")
def _write_headers(self, msg): # This is almost the same as the string version, except for handling # strings with 8bit bytes. for h, v in msg._headers: self.write('%s: ' % h) if isinstance(v, str): if _has_surrogates(v): if not self.policy.must_be_7bit: # If we have raw 8bit data in a byte string, we have no idea # what the encoding is. There is no safe way to split this # string. If it's ascii-subset, then we could do a normal # ascii split, but if it's multibyte then we could break the # string. There's no way to know so the least harm seems to # be to not split the string and risk it being too long. self.write(v+NL) continue h = Header(v, charset=_charset.UNKNOWN8BIT, header_name=h) else: h = Header(v, header_name=h) else: # Assume it is a Header-like object. h = v self.write(h.encode(linesep=self._NL, maxlinelen=self._maxheaderlen)+self._NL) # A blank line always separates headers from body self.write(self._NL)
def encode_param(key, name, value): try: value = value.encode("ascii") return email.message._formatparam(name, value) except Exception: value = Header(value.encode("utf-8"), "utf-8", header_name=key).encode(splitchars=' ;,') return email.message._formatparam(name, value)
def to_mail(to_name, to_email, subject, body, headers={}, decorate_body=True): try: email_from = config.get("adhocracy.email.from") if decorate_body: body = ( _(u"Hi %s,") % to_name + u"\r\n\r\n%s\r\n\r\n" % body + _(u"Cheers,\r\n\r\n" u" the %s Team\r\n") % config.get("adhocracy.site.name") ) msg = MIMEText(body.encode(ENCODING), "plain", ENCODING) for k, v in headers.items(): msg[k] = v subject = Header(subject.encode(ENCODING), ENCODING) msg["Subject"] = subject msg["From"] = _("%s <%s>") % (config.get("adhocracy.site.name"), email_from) to = Header(u"%s <%s>" % (to_name, to_email), ENCODING) msg["To"] = to msg["Date"] = email.Utils.formatdate(time()) msg["X-Mailer"] = "Adhocracy SMTP %s" % version.get_version() # log.debug("MAIL\r\n" + msg.as_string()) send(email_from, to_email, msg.as_string()) except Exception: log.exception("Sending mail failed.")
def _mail_recipient(recipient_name, recipient_email, sender_name, sender_url, subject, body, headers={}): mail_from = config.get('ckan.mail_from') body = add_msg_niceties(recipient_name, body, sender_name, sender_url) msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8') for k, v in headers.items(): msg[k] = v subject = Header(subject.encode('utf-8'), 'utf-8') msg['Subject'] = subject msg['From'] = _("%s <%s>") % (sender_name, mail_from) recipient = u"%s <%s>" % (recipient_name, recipient_email) msg['To'] = Header(recipient, 'utf-8') msg['Date'] = Utils.formatdate(time()) msg['X-Mailer'] = "CKAN %s" % __version__ try: server = smtplib.SMTP( config.get('test_smtp_server', config.get('smtp_server', 'localhost'))) #server.set_debuglevel(1) server.sendmail(mail_from, [recipient_email], msg.as_string()) server.quit() except Exception, e: msg = '%r' % e log.exception(msg) raise MailerException(msg)
def _mail_recipient(recipient_name, recipient_email, sender_name, sender_url, subject, body, headers={}): mail_from = config.get('smtp.mail_from') body = add_msg_niceties(recipient_name, body, sender_name, sender_url) msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8') for k, v in headers.items(): msg[k] = v subject = Header(subject.encode('utf-8'), 'utf-8') msg['Subject'] = subject msg['From'] = _("%s <%s>") % (sender_name, mail_from) recipient = u"%s <%s>" % (recipient_name, recipient_email) msg['To'] = Header(recipient, 'utf-8') msg['Date'] = Utils.formatdate(time()) msg['X-Mailer'] = "CKAN %s" % ckan.__version__ # Send the email using Python's smtplib. smtp_connection = smtplib.SMTP() if 'smtp.test_server' in config: # If 'smtp.test_server' is configured we assume we're running tests, # and don't use the smtp.server, starttls, user, password etc. options. smtp_server = config['smtp.test_server'] smtp_starttls = False smtp_user = None smtp_password = None else: smtp_server = config.get('smtp.server', 'localhost') smtp_starttls = paste.deploy.converters.asbool( config.get('smtp.starttls')) smtp_user = config.get('smtp.user') smtp_password = config.get('smtp.password') smtp_connection.connect(smtp_server) try: #smtp_connection.set_debuglevel(True) # Identify ourselves and prompt the server for supported features. smtp_connection.ehlo() # If 'smtp.starttls' is on in CKAN config, try to put the SMTP # connection into TLS mode. if smtp_starttls: if smtp_connection.has_extn('STARTTLS'): smtp_connection.starttls() # Re-identify ourselves over TLS connection. smtp_connection.ehlo() else: raise MailerException("SMTP server does not support STARTTLS") # If 'smtp.user' is in CKAN config, try to login to SMTP server. if smtp_user: assert smtp_password, ("If smtp.user is configured then " "smtp.password must be configured as well.") smtp_connection.login(smtp_user, smtp_password) smtp_connection.sendmail(mail_from, [recipient_email], msg.as_string()) log.info("Sent email to {0}".format(recipient_email)) except smtplib.SMTPException, e: msg = '%r' % e log.exception(msg) raise MailerException(msg)
def encode_string(name, value, maxlinelen=None): try: header = Header(value.encode("ascii"), "ascii", maxlinelen, header_name=name) except UnicodeEncodeError: header = Header(value.encode("utf-8"), "utf-8", header_name=name) return header.encode(splitchars=' ;,')
def test_japanese_codecs(self): eq = self.ndiffAssertEqual j = Charset('euc-jp') g = Charset('iso-8859-1') h = Header('Hello World!') jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa' ghello = 'Gr\xfc\xdf Gott!' h.append(jhello, j) h.append(ghello, g) eq(h.encode(), 'Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?=\n =?iso-8859-1?q?Gr=FC=DF?= =?iso-8859-1?q?_Gott!?=') eq(decode_header(h.encode()), [('Hello World!', None), ('\x1b$B%O%m!<%o!<%k%I!*\x1b(B', 'iso-2022-jp'), ('Gr\xfc\xdf Gott!', 'iso-8859-1')]) long = 'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9' h = Header(long, j, header_name='Subject') enc = h.encode() eq(enc, '=?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?=\n =?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=') eq(h.__unicode__().encode('euc-jp'), long) return None
def encode_address(address, encoding): parts = re.split("<|>", address.replace('"', "")) name = parts[0] if len(parts) > 1: name = Header(name.encode(encoding.lower()), encoding.upper()).encode() name += " <" + parts[1] + ">" return name
def encode_header(self, value): """ Encode an HTTP header value. Try first natively in ISO-8859-1, then UTF-8 encoded quoted string. """ try: return smart_unicode(value).encode('iso-8859-1') except UnicodeEncodeError: header = Header(smart_unicode(value), 'utf-8') return header.encode()
def test_unicode_addresses(mailer): msg = mailer.mail( subject="subject", sender=u'ÄÜÖ → ✓ <*****@*****.**>', recipients=[u"Ä <*****@*****.**>", u"Ü <*****@*****.**>"], cc=[u"Ö <*****@*****.**>"]) msg_as_string = str(msg) a1 = sanitize_address(u"Ä <*****@*****.**>") a2 = sanitize_address(u"Ü <*****@*****.**>") h1_a = Header("To: %s, %s" % (a1, a2)) h1_b = Header("To: %s, %s" % (a2, a1)) h2 = Header("From: %s" % sanitize_address(u"ÄÜÖ → ✓ <*****@*****.**>")) h3 = Header("Cc: %s" % sanitize_address(u"Ö <*****@*****.**>")) try: assert h1_a.encode() in msg_as_string except AssertionError: assert h1_b.encode() in msg_as_string assert h2.encode() in msg_as_string assert h3.encode() in msg_as_string
def test_japanese_codecs(self): if due_to_ironpython_bug("http://tkbgitvstfat01:8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=360541"): return eq = self.ndiffAssertEqual j = Charset("euc-jp") g = Charset("iso-8859-1") h = Header("Hello World!") jhello = "\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa" ghello = "Gr\xfc\xdf Gott!" h.append(jhello, j) h.append(ghello, g) # BAW: This used to -- and maybe should -- fold the two iso-8859-1 # chunks into a single encoded word. However it doesn't violate the # standard to have them as two encoded chunks and maybe it's # reasonable <wink> for each .append() call to result in a separate # encoded word. eq( h.encode(), """\ Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?= =?iso-8859-1?q?Gr=FC=DF?= =?iso-8859-1?q?_Gott!?=""", ) eq( decode_header(h.encode()), [ ("Hello World!", None), ("\x1b$B%O%m!<%o!<%k%I!*\x1b(B", "iso-2022-jp"), ("Gr\xfc\xdf Gott!", "iso-8859-1"), ], ) long = "test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9" h = Header(long, j, header_name="Subject") # test a very long header enc = h.encode() # TK: splitting point may differ by codec design and/or Header encoding eq( enc, """\ =?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?= =?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=""", ) # TK: full decode comparison eq(h.__unicode__().encode("euc-jp"), long)
def test_reply_to(self): msg = Message(subject="testing", recipients=["*****@*****.**"], sender="spammer <*****@*****.**>", reply_to="somebody <*****@*****.**>", body="testing") response = msg.as_string() h = Header("Reply-To: %s" % sanitize_address('somebody <*****@*****.**>')) self.assertIn(h.encode(), str(response))
def test_reply_to(mailer): msg = mailer.mail( subject="testing", recipients=["*****@*****.**"], sender="spammer <*****@*****.**>", reply_to="somebody <*****@*****.**>", body="testing") h = Header( "Reply-To: %s" % sanitize_address('somebody <*****@*****.**>')) assert h.encode() in str(msg)
def modify_header(self, *args): '''Generate the content for the :mailheader:`Sender` header. :returns: The *mailbox* of the group (a display-name and an angle-address). :rtype: str''' name = to_unicode_or_bust(self.groupInfo.name) h = Header(name, UTF8) headerName = h.encode() addr = self.listInfo.get_property('mailto') retval = formataddr((headerName, addr)) return retval
def _write_headers(self, msg): for h, v in msg.items(): print("%s:" % h, end=" ", file=self._fp) if isinstance(v, Header): print(v.encode(maxlinelen=self._maxheaderlen), file=self._fp) else: # Header's got lots of smarts, so use it. header = Header(v, maxlinelen=self._maxheaderlen, header_name=h) print(header.encode(), file=self._fp) # A blank line always separates headers from body print(file=self._fp)
def receivedHeader(self, helo, origin, rcpt): recv = "from {hello0} [{hello1}] message to {rcpts}; {date}" rcpts = ",".join([str(r.dest) for r in rcpt]) date = utils.format_datetime(datetime.datetime.now()) hh = Header("Received") hh.append( recv.format(hello0=helo[0].decode('ascii'), hello1=helo[1].decode('ascii'), rcpts=rcpts, date=date).encode('ascii')) return hh.encode().encode('ascii')
def enc_addresses(addr_list): addr = [] enc_addr = getaddresses(addr_list) for a in enc_addr: h = Header() h.append(a[0]) h.append('<' + a[1] + '>') addr.append(h.encode()) return ','.join(addr)
def _formataddr(mailbox, display_name=None, header_name=None): header = Header(header_name=header_name) if display_name: display_name_no_control_chars = remove_control_chars(display_name) header.append(display_name_no_control_chars) if _SPECIALS.search(header.encode()): header = Header(header_name=header_name) header.append('"%s"' % email.utils.quote(display_name_no_control_chars)) header.append("<%s>" % encode_domain_as_idna(mailbox)) else: header.append(encode_domain_as_idna(mailbox)) return header
def _write_headers(self, msg): for h, v in msg.items(): print('%s:' % h, end=' ', file=self._fp) if isinstance(v, Header): print(v.encode(maxlinelen=self._maxheaderlen), file=self._fp) else: # Header's got lots of smarts, so use it. header = Header(v, maxlinelen=self._maxheaderlen, header_name=h) print(header.encode(), file=self._fp) # A blank line always separates headers from body print(file=self._fp)
def test_internationalised_subject4(self): path = os.path.join(self.examineDir, "internationalised_subject_complex.pdf") header = Header() header.append(bytes('£100', 'iso-8859-1'), 'iso-8859-1') header.append(bytes(' is != how much ', 'utf-8'), 'utf-8') header.append(bytes('I have to spend!', 'iso-8859-15'), 'iso-8859-15') self.addHeaders(subject=header.encode()) error = self.invokeDirectly(outputFile=path, extraParams=['--headers']) self.assertTrue(os.path.exists(path)) self.assertEqual('', error) self.assertFalse(self.existsByTimeWarning()) self.assertFalse(self.existsByTimeOriginal())
def test_unicode_headers(self): msg = Message(subject="subject", sender=u'ÄÜÖ → ✓ <*****@*****.**>', recipients=[u"Ä <*****@*****.**>", u"Ü <*****@*****.**>"], cc=[u"Ö <*****@*****.**>"]) response = msg.as_string() a1 = sanitize_address(u"Ä <*****@*****.**>") a2 = sanitize_address(u"Ü <*****@*****.**>") h1_a = Header("To: %s, %s" % (a1, a2)) h1_b = Header("To: %s, %s" % (a2, a1)) h2 = Header("From: %s" % sanitize_address(u"ÄÜÖ → ✓ <*****@*****.**>")) h3 = Header("Cc: %s" % sanitize_address(u"Ö <*****@*****.**>")) # Ugly, but there's no guaranteed order of the recipieints in the header try: self.assertIn(h1_a.encode(), response) except AssertionError: self.assertIn(h1_b.encode(), response) self.assertIn(h2.encode(), response) self.assertIn(h3.encode(), response)
def _write_headers(self, msg): for h, v in msg.items(): self.write('%s: ' % h) if isinstance(v, Header): self.write(v.encode( maxlinelen=self._maxheaderlen, linesep=self._NL)+self._NL) else: # Header's got lots of smarts, so use it. header = Header(v, maxlinelen=self._maxheaderlen, header_name=h) self.write(header.encode(linesep=self._NL)+self._NL) # A blank line always separates headers from body self.write(self._NL)
def test_japanese_codecs(self): eq = self.ndiffAssertEqual jcode = "euc-jp" gcode = "iso-8859-1" j = Charset(jcode) g = Charset(gcode) h = Header("Hello World!") jhello = str(b'\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc' b'\xa5\xeb\xa5\xc9\xa1\xaa', jcode) ghello = str(b'Gr\xfc\xdf Gott!', gcode) h.append(jhello, j) h.append(ghello, g) # BAW: This used to -- and maybe should -- fold the two iso-8859-1 # chunks into a single encoded word. However it doesn't violate the # standard to have them as two encoded chunks and maybe it's # reasonable <wink> for each .append() call to result in a separate # encoded word. eq(h.encode(), """\ Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?= =?iso-8859-1?q?Gr=FC=DF_Gott!?=""") eq(decode_header(h.encode()), [(b'Hello World! ', None), (b'\x1b$B%O%m!<%o!<%k%I!*\x1b(B', 'iso-2022-jp'), (b'Gr\xfc\xdf Gott!', gcode)]) subject_bytes = (b'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5' b'\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2' b'\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3' b'\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9') subject = str(subject_bytes, jcode) h = Header(subject, j, header_name="Subject") # test a very long header enc = h.encode() # TK: splitting point may differ by codec design and/or Header encoding eq(enc , """\ =?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?= =?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=""") # TK: full decode comparison eq(str(h).encode(jcode), subject_bytes)
def add_header(self, key, value, immediate=False): """adds a header to the message. by default, headers will added when re-injecting the message back to postfix if you set immediate=True the message source will be replaced immediately. Only set this to true if a header must be visible to later plugins (eg. for spamassassin rules), otherwise, leave as False which is faster. """ if immediate: # is ignore the right thing to do here? value.encode('UTF-8', 'ignore') hdr = Header(value, header_name=key, continuation_ws=' ') hdrline = "%s: %s\n" % (key, hdr.encode()) src = hdrline + self.get_source() self.set_source(src) else: self.addheaders[key] = value
def test_japanese_codecs(self): if due_to_ironpython_bug( "http://tkbgitvstfat01:8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=360541" ): return eq = self.ndiffAssertEqual j = Charset("euc-jp") g = Charset("iso-8859-1") h = Header("Hello World!") jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa' ghello = 'Gr\xfc\xdf Gott!' h.append(jhello, j) h.append(ghello, g) # BAW: This used to -- and maybe should -- fold the two iso-8859-1 # chunks into a single encoded word. However it doesn't violate the # standard to have them as two encoded chunks and maybe it's # reasonable <wink> for each .append() call to result in a separate # encoded word. eq( h.encode(), """\ Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?= =?iso-8859-1?q?Gr=FC=DF?= =?iso-8859-1?q?_Gott!?=""") eq(decode_header(h.encode()), [('Hello World!', None), ('\x1b$B%O%m!<%o!<%k%I!*\x1b(B', 'iso-2022-jp'), ('Gr\xfc\xdf Gott!', 'iso-8859-1')]) long = 'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9' h = Header(long, j, header_name="Subject") # test a very long header enc = h.encode() # TK: splitting point may differ by codec design and/or Header encoding eq( enc, """\ =?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?= =?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=""") # TK: full decode comparison eq(h.__unicode__().encode('euc-jp'), long)
def buildmsgsource(suspect): """Build the message source with fuglu headers prepended""" # we must prepend headers manually as we can't set a header order in email # objects origmsgtxt = suspect.get_source() newheaders = "" for key in suspect.addheaders: # is ignore the right thing to do here? val = suspect.addheaders[key] val.encode('UTF-8', 'ignore') #self.logger.debug('Adding header %s : %s'%(key,val)) hdr = Header(val, header_name=key, continuation_ws=' ') newheaders += "%s: %s\n" % (key, hdr.encode()) modifiedtext = newheaders + origmsgtxt return modifiedtext
def to_mail(to_name, to_email, subject, body, headers={}, decorate_body=True, email_from=None, reply_to=None, name_from=None): try: if email_from is None: email_from = config.get('adhocracy.email.from') if name_from is None: name_from = config.get('adhocracy.site.name') if decorate_body: body = ( _(u"Hi %s,") % to_name + u"\r\n\r\n%s\r\n\r\n" % body + _(u"Cheers,\r\n\r\n" u" the %s Team\r\n") % config.get('adhocracy.site.name')) # wrap body, but leave long words (e.g. links) intact body = u'\n'.join( textwrap.fill(line, break_long_words=False, break_on_hyphens=False) for line in body.split(u'\n')) msg = MIMEText(body.encode(ENCODING), 'plain', ENCODING) for k, v in headers.items(): msg[k] = v subject = Header(subject.encode(ENCODING), ENCODING) msg['Subject'] = subject msg['From'] = _("%s <%s>") % (name_from, email_from) to = Header(u"%s <%s>" % (to_name, to_email), ENCODING) msg['To'] = to if reply_to is not None: msg['Reply-To'] = reply_to msg[''] msg['Date'] = email.Utils.formatdate(time()) msg['X-Mailer'] = "Adhocracy SMTP %s" % version.get_version() # log.debug("MAIL\r\n" + msg.as_string()) send(email_from, to_email, msg.as_string()) except Exception: log.exception("Sending mail failed.")
def _mail_recipient(recipient_name, recipient_email, sender_name, sender_url, subject, body, headers={}): mail_from = config.get('smtp.mail_from') msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8') for k, v in headers.items(): if k in msg.keys(): msg.replace_header(k, v) else: msg.add_header(k, v) subject = Header(subject.encode('utf-8'), 'utf-8') msg['Subject'] = subject msg['From'] = _("%s <%s>") % (sender_name, mail_from) recipient = u"%s <%s>" % (recipient_name, recipient_email) msg['To'] = Header(recipient, 'utf-8') msg['Date'] = Utils.formatdate(time()) msg['X-Mailer'] = "CKAN %s" % ckan.__version__ # Send the email using Python's smtplib. smtp_connection = smtplib.SMTP() if 'smtp.test_server' in config: # If 'smtp.test_server' is configured we assume we're running tests, # and don't use the smtp.server, starttls, user, password etc. options. smtp_server = config['smtp.test_server'] smtp_starttls = False smtp_user = None smtp_password = None else: smtp_server = config.get('smtp.server', 'localhost') smtp_starttls = paste.deploy.converters.asbool( config.get('smtp.starttls')) smtp_user = config.get('smtp.user') smtp_password = config.get('smtp.password') try: smtp_connection.connect(smtp_server) except socket.error, e: log.exception(e) raise MailerException( 'SMTP server could not be connected to: "%s" %s' % (smtp_server, e))
def fromAddr(siteInfo): '''Get the formatted ``From`` address for a given site :param siteInfo: The site for which the From address will be created. :type siteInfo: :class:`Products.GSContent.interfaces.IGSSiteInfo` :returns: A formatted email address consisting of the site-name and the support email address: ``Example Groups Support <*****@*****.**>``. :rtype: str ''' siteName = _('notify-anonymous-support-name', '${siteName} Support', mapping={'siteName': siteInfo.name}) translatedSiteName = translate(siteName) headerName = Header(translatedSiteName, UTF8) encodedName = headerName.encode() addr = siteInfo.get_support_email() retval = formataddr((encodedName, addr)) return retval
def modify_headers(self, email): '''Set the headers in an email message to the "correct" values :param email: The email message to modify. :type email: :class:`email.message.Message` :returns: The modified email message. :rtype: :class:`email.message.Message` The :meth:`HeaderModifier.modify_headers` method acquires the header-adaptors (which conform to the :class:`.interfaces.IEmailHeaderModifier` interface). It then itterates through the adaptors (one per header) and then modifies the :obj:`email` based on the output of the header-adaptor: ``None``: The header is deleted. ``str``: The header is set to the string. ``unicode``: The output is encoded (using :class:`email.header.Header`) and the header is set to the string. ''' gsm = getGlobalSiteManager() for name, adaptor in gsm.getAdapters((self.group, self.request), IEmailHeaderModifier): nv = adaptor.modify_header(email) if nv is None: # From the email.message docs: # No exception is raised if the named field isn't present # in the headers. del(email[name]) else: if type(nv) == bytes: # == str in Python 2 newValue = nv else: # Unicode hv = Header(nv, 'utf-8') newValue = hv.encode() if name in email: email.replace_header(name, newValue) else: email.add_header(name, newValue) return email
def attach_csv(self, source, filename): if not self._msg: return ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) base = MIMEBase(maintype, subtype) with open('%s/%s' % (source, filename), 'rb') as fp: base.set_payload(fp.read()) encoders.encode_base64(base) header = Header(filename, charset=default_unicode) base.add_header('Content-Disposition', 'attachment', filename='%s' % header.encode()) self._msg.attach(base) fp.close()
def generate_relay_From(original_from_address): relay_display_name, relay_from_address = parseaddr( settings.RELAY_FROM_ADDRESS) # RFC 2822 (https://tools.ietf.org/html/rfc2822#section-2.1.1) # says email header lines must not be more than 998 chars long. # Encoding display names to longer than 998 chars will add wrap # characters which are unsafe. (See https://bugs.python.org/issue39073) # So, truncate the original sender to 900 chars so we can add our # "[via Relay] <relayfrom>" and encode it all. if len(original_from_address) > 998: original_from_address = '%s ...' % original_from_address[:900] # line breaks in From: will encode to unsafe chars, so strip them. original_from_address = (original_from_address.replace( '\u2028', '').replace('\r', '').replace('\n', '')) display_name = Header('"%s [via Relay]"' % (original_from_address), 'UTF-8') formatted_from_address = str( Address(display_name.encode(maxlinelen=998), addr_spec=relay_from_address)) return formatted_from_address
def mail_recipient(recipient_name, recipient_email, subject, body, headers={}): mail_from = config.get('openspending.mail_from', '*****@*****.**') body = add_msg_niceties(recipient_name, body, app_globals.site_title) msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8') for k, v in headers.items(): msg[k] = v subject = Header(subject.encode('utf-8'), 'utf-8') msg['Subject'] = subject msg['From'] = _("%s <%s>") % (app_globals.site_title, mail_from) recipient = u"%s <%s>" % (recipient_name, recipient_email) msg['To'] = Header(recipient, 'utf-8') msg['Date'] = Utils.formatdate(time()) msg['X-Mailer'] = "OpenSpending" try: server = smtplib.SMTP(config.get('smtp_server', 'localhost')) server.sendmail(mail_from, [recipient_email], msg.as_string()) server.quit() except Exception, e: msg = '%r' % e log.exception(msg) raise MailerException(msg)
def forbid_multi_line_headers(name, val, encoding): """Forbids multi-line headers, to prevent header injection.""" encoding = encoding or 'utf-8' val = force_unicode(val, encoding) if '\n' in val or '\r' in val: raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name)) try: val = val.encode('ascii') except UnicodeEncodeError: if name.lower() in ('to', 'from', 'cc'): result = [] for nm, addr in getaddresses((val,)): nm = str(Header(nm.encode(encoding), encoding)) result.append(formataddr((nm, str(addr)))) val = ', '.join(result) else: val = Header(val.encode(encoding), encoding) else: if name.lower() == 'subject': val = Header(val) return name, val
def buildmsgsource(suspect): """Build the message source with fuglu headers prepended""" # we must prepend headers manually as we can't set a header order in email # objects # -> the original message source is bytes origmsgtxt = suspect.get_source() newheaders = "" for key in suspect.addheaders: # is ignore the right thing to do here? val = suspect.addheaders[key] #self.logger.debug('Adding header %s : %s'%(key,val)) hdr = Header(val, header_name=key, continuation_ws=' ') newheaders += "%s: %s\r\n" % (key, hdr.encode()) # the original message should be in bytes, make sure the header added # is an encoded string as well modifiedtext = force_bString(newheaders) + force_bString(origmsgtxt) return modifiedtext
def send_test(subject, document, filename, html, **kw): if subject: msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = kw.get('addr_from') msg['To'] = kw.get('addr_to') if html: msg.attach(MIMEText(html, 'html')) if isinstance(document, bytes): fp = io.BytesIO(document) else: fp = io.BytesIO() document.save(fp) ctype = kw.get( 'ctype' ) or 'application/msword' #octet-stream vnd.ms-excel application/pdf vnd.ms-powerpoint image/png maintype, subtype = ctype.split('/', 1) base = MIMEBase(maintype, subtype) fp.seek(0) base.set_payload(fp.read()) encoders.encode_base64(base) header = Header(filename, charset=default_unicode) base.add_header('Content-Disposition', 'attachment', filename='%s' % header.encode()) msg.attach(base) smtp = smtplib.SMTP(smtphost['host'], smtphost['port']) smtp.send_message(msg) smtp.quit() fp.close() return 1
def _write_headers(self, msg): # This is almost the same as the string version, except for handling # strings with 8bit bytes. for h, v in msg._headers: self.write('%s: ' % h) if isinstance(v, Header): self.write(v.encode(maxlinelen=self._maxheaderlen)+NL) elif _has_surrogates(v): # If we have raw 8bit data in a byte string, we have no idea # what the encoding is. There is no safe way to split this # string. If it's ascii-subset, then we could do a normal # ascii split, but if it's multibyte then we could break the # string. There's no way to know so the least harm seems to # be to not split the string and risk it being too long. self.write(v+NL) else: # Header's got lots of smarts and this string is safe... header = Header(v, maxlinelen=self._maxheaderlen, header_name=h) self.write(header.encode(linesep=self._NL)+self._NL) # A blank line always separates headers from body self.write(self._NL)
def encode_header(key, value): """ encodes a unicode string as a valid header value :param key: the header field this value will be stored in :type key: str :param value: the value to be encoded :type value: unicode """ # handle list of "realname <email>" entries separately if key.lower() in ['from', 'to', 'cc', 'bcc']: rawentries = email.utils.getaddresses([value]) encodedentries = [] for name, address in rawentries: # try to encode as ascii, if that fails, revert to utf-8 # name must be a unicode string here namepart = Header(name) # append address part encoded as ascii entry = email.utils.formataddr((namepart.encode(), address)) encodedentries.append(entry) value = Header(', '.join(encodedentries)) else: value = Header(value) return value
def send_raw(self, job, message, config): config = dict(self.middleware.call_sync('mail.config'), **config) if config['fromname']: from_addr = Header(config['fromname'], 'utf-8') try: config['fromemail'].encode('ascii') except UnicodeEncodeError: from_addr.append(f'<{config["fromemail"]}>', 'utf-8') else: from_addr.append(f'<{config["fromemail"]}>', 'ascii') else: try: config['fromemail'].encode('ascii') except UnicodeEncodeError: from_addr = Header(config['fromemail'], 'utf-8') else: from_addr = Header(config['fromemail'], 'ascii') interval = message.get('interval') if interval is None: interval = timedelta() else: interval = timedelta(seconds=interval) sw_name = self.middleware.call_sync('system.version').split('-', 1)[0] channel = message.get('channel') if not channel: channel = sw_name.lower() if interval > timedelta(): channelfile = '/tmp/.msg.%s' % (channel) last_update = datetime.now() - interval try: last_update = datetime.fromtimestamp( os.stat(channelfile).st_mtime) except OSError: pass timediff = datetime.now() - last_update if (timediff >= interval) or (timediff < timedelta()): # Make sure mtime is modified # We could use os.utime but this is simpler! with open(channelfile, 'w') as f: f.write('!') else: raise CallError( 'This message was already sent in the given interval') verrors = self.__password_verify(config['pass'], 'mail-config.pass') if verrors: raise verrors to = message.get('to') if not to: to = [ self.middleware.call_sync('user.query', [('username', '=', 'root')], {'get': True})['email'] ] if not to[0]: raise CallError('Email address for root is not configured') if message.get('attachments'): job.check_pipe("input") def read_json(): f = job.pipes.input.r data = b'' i = 0 while True: read = f.read(1048576) # 1MiB if read == b'': break data += read i += 1 if i > 50: raise ValueError( 'Attachments bigger than 50MB not allowed yet') if data == b'': return None return json.loads(data) attachments = read_json() else: attachments = None if 'html' in message or attachments: msg = MIMEMultipart() msg.preamble = 'This is a multi-part message in MIME format.' if 'html' in message: msg2 = MIMEMultipart('alternative') msg2.attach( MIMEText(message['text'], 'plain', _charset='utf-8')) msg2.attach(MIMEText(message['html'], 'html', _charset='utf-8')) msg.attach(msg2) if attachments: for attachment in attachments: m = Message() m.set_payload(attachment['content']) for header in attachment.get('headers'): m.add_header(header['name'], header['value'], **(header.get('params') or {})) msg.attach(m) else: msg = MIMEText(message['text'], _charset='utf-8') msg['Subject'] = message['subject'] msg['From'] = from_addr msg['To'] = ', '.join(to) if message.get('cc'): msg['Cc'] = ', '.join(message.get('cc')) msg['Date'] = formatdate() local_hostname = self.middleware.call_sync('system.hostname') msg['Message-ID'] = "<%s-%s.%s@%s>" % ( sw_name.lower(), datetime.utcnow().strftime("%Y%m%d.%H%M%S.%f"), base64.urlsafe_b64encode(os.urandom(3)), local_hostname) extra_headers = message.get('extra_headers') or {} for key, val in list(extra_headers.items()): # We already have "Content-Type: multipart/mixed" and setting "Content-Type: text/plain" like some scripts # do will break python e-mail module. if key.lower() == "content-type": continue if key in msg: msg.replace_header(key, val) else: msg[key] = val syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_MAIL) try: if config['oauth']: self.middleware.call_sync('mail.gmail_send', msg, config) else: server = self._get_smtp_server(config, message['timeout'], local_hostname=local_hostname) # NOTE: Don't do this. # # If smtplib.SMTP* tells you to run connect() first, it's because the # mailserver it tried connecting to via the outgoing server argument # was unreachable and it tried to connect to 'localhost' and barfed. # This is because FreeNAS doesn't run a full MTA. # else: # server.connect() headers = '\n'.join([f'{k}: {v}' for k, v in msg._headers]) syslog.syslog(f"sending mail to {', '.join(to)}\n{headers}") server.sendmail(from_addr.encode(), to, msg.as_string()) server.quit() except Exception as e: # Don't spam syslog with these messages. They should only end up in the # test-email pane. # We are only interested in ValueError, not subclasses. if e.__class__ is ValueError: raise CallError(str(e)) syslog.syslog(f'Failed to send email to {", ".join(to)}: {str(e)}') if isinstance(e, smtplib.SMTPAuthenticationError): raise CallError( f'Authentication error ({e.smtp_code}): {e.smtp_error}', errno.EAUTH if osc.IS_FREEBSD else errno.EPERM) self.logger.warn('Failed to send email: %s', str(e), exc_info=True) if message['queue']: with MailQueue() as mq: mq.append(msg) raise CallError(f'Failed to send email: {e}') return True
def generate_relay_From(original_from_address): relay_display_name, relay_from_address = parseaddr( settings.RELAY_FROM_ADDRESS) display_name = Header( '"' + quote('%s [via Relay]' % (original_from_address)) + '"', 'UTF-8') return relay_from_address, display_name.encode()
def create(self): """ Create an auto response object from whole cloth. The auto response is a MIME compliant entity with either one or two bodyparts, depending on what Defaults.AUTORESPONSE_INCLUDE_SENDER_COPY is set to. In most cases, the object will look like: multipart/mixed text/plain (response text) message/rfc822 or text/rfc822-headers (sender's message) """ # Headers that users shouldn't be setting in their templates. bad_headers = ['MIME-Version', 'Content-Type', 'BodyCharset', 'Content-Transfer-Encoding', 'Content-Disposition', 'Content-Description'] for h in bad_headers: if self.bouncemsg.has_key(h): del self.bouncemsg[h] textpart = MIMEText(self.bouncemsg.get_payload(), 'plain', self.bodycharset) bodyparts = 1 + Defaults.AUTORESPONSE_INCLUDE_SENDER_COPY if bodyparts == 1: # A single text/plain entity. self.mimemsg = textpart elif bodyparts > 1: # A multipart/mixed entity with two bodyparts. self.mimemsg = MIMEMultipart('mixed') if self.responsetype == 'request': textpart['Content-Description'] = 'Confirmation Request' elif self.responsetype == 'accept': textpart['Content-Description'] = 'Confirmation Acceptance' elif self.responsetype == 'bounce': textpart['Content-Description'] = 'Failure Notice' textpart['Content-Disposition'] = 'inline' self.mimemsg.attach(textpart) if Defaults.AUTORESPONSE_INCLUDE_SENDER_COPY == 1: # include the headers only as a text/rfc822-headers part. rfc822part = MIMEText( self.msgin_as_string[:self.msgin_as_string.index('\n\n')+1], 'rfc822-headers', self.msgin.get_charsets(DEFAULT_CHARSET)[0]) rfc822part['Content-Description'] = 'Original Message Headers' elif Defaults.AUTORESPONSE_INCLUDE_SENDER_COPY == 2: # include the entire message as a message/rfc822 part. # If the message was > CONFIRM_MAX_MESSAGE_SIZE, it has already # been truncated appropriately in the constructor. rfc822part = MIMEMessage(self.msgin) rfc822part['Content-Description'] = 'Original Message' rfc822part['Content-Disposition'] = 'inline' self.mimemsg.attach(rfc822part) # RFC 2183 section 2.10 permits the use Content-Disposition in # the main body of the message. self.mimemsg['Content-Disposition'] = 'inline' # fold the template headers into the main entity. for k, v in self.bouncemsg.items(): ksplit = k.split('.', 1) if len(ksplit) == 1: hdrcharset = DEFAULT_CHARSET else: # Header.CHARSET: Value k = ksplit[0] hdrcharset = ksplit[1] # headers like `From:' which contain e-mail addresses # might need the "Fullname" portion encoded, but the # address portion must never be encoded. if k.lower() in map(lambda s: s.lower(), Defaults.TEMPLATE_EMAIL_HEADERS): name, addr = parseaddr(v) if name and hdrcharset.lower() not in ('ascii', 'us-ascii'): h = Header(name, hdrcharset, errors='replace') name = h.encode() self.mimemsg[k] = formataddr((name, addr)) # headers like `Subject:' might contain an encoded string, # so we need to decode that first before encoding the # entire header value. elif hdrcharset.lower() not in ('ascii', 'us-ascii') and \ k.lower() in map(lambda s: s.lower(), Defaults.TEMPLATE_ENCODED_HEADERS): h = Header(charset=hdrcharset, header_name=k, errors='replace') decoded_seq = decode_header(v) for s, charset in decoded_seq: h.append(s, charset) self.mimemsg[k] = h else: self.mimemsg[k] = Header(v, hdrcharset, header_name=k, errors='replace') # Add some new headers to the main entity. timesecs = time.time() self.mimemsg['Date'] = Util.make_date(timesecs) # required by RFC 2822 self.mimemsg['Message-ID'] = Util.make_msgid(timesecs) # Ditto # References refs = [] for h in ['references', 'message-id']: if self.msgin.has_key(h): refs = refs + self.msgin.get(h).split() if refs: self.mimemsg['References'] = '\n\t'.join(refs) # In-Reply-To if self.msgin.has_key('message-id'): self.mimemsg['In-Reply-To'] = self.msgin.get('message-id') self.mimemsg['To'] = self.recipient # Some auto responders respect this header. self.mimemsg['Precedence'] = 'bulk' # Auto-Submitted per draft-moore-auto-email-response-00.txt if self.responsetype in ('request', 'accept'): self.mimemsg['Auto-Submitted'] = 'auto-replied' elif self.responsetype == 'bounce': self.mimemsg['Auto-Submitted'] = 'auto-generated (failure)' self.mimemsg['X-Delivery-Agent'] = 'TMDA/%s (%s)' % (Version.TMDA, Version.CODENAME) # Optionally, add some custom headers. Util.add_headers(self.mimemsg, Defaults.ADDED_HEADERS_SERVER) # Optionally, remove some headers. Util.purge_headers(self.mimemsg, Defaults.PURGED_HEADERS_SERVER)
def _mail_recipient_html(sender_name='Humanitarian Data Exchange (HDX)', sender_email='*****@*****.**', recipients_list=None, subject=None, content_dict=None, cc_recipients_list=None, bcc_recipients_list=None, footer=True, headers={}, reply_wanted=False, snippet='email/email.html', file=None): if sender_email: mail_from = sender_email else: mail_from = config.get( 'hdx_smtp.mail_from_please_reply') if reply_wanted else config.get( 'smtp.mail_from') template_data = { 'data': { 'data': content_dict, 'footer': footer, '_snippet': snippet }, } body_html = mailer.render_jinja2('email/email.html', template_data) # msg = MIMEMultipart('alternative') msg = MIMEMultipart() for k, v in headers.items(): msg[k] = v subject = Header(subject.encode('utf-8'), 'utf-8') msg['Subject'] = subject msg['From'] = _(u"%s <%s>") % (sender_name, mail_from) recipient_email_list = [] recipients = None if recipients_list: for r in recipients_list: email = r.get('email') recipient_email_list.append(email) display_name = r.get('display_name') if display_name: recipient = u"%s <%s>" % (display_name, email) else: recipient = u"%s" % email # else: # no recipient list provided recipients = ', '.join([recipients, recipient ]) if recipients else recipient msg['To'] = Header(recipients, 'utf-8') if bcc_recipients_list: for r in bcc_recipients_list: recipient_email_list.append(r.get('email')) cc_recipients = None if cc_recipients_list: for r in cc_recipients_list: recipient_email_list.append(r.get('email')) cc_recipient = u"%s <%s>" % (r.get('display_name'), r.get('email')) cc_recipients = ', '.join([cc_recipients, cc_recipient ]) if cc_recipients else cc_recipient msg['Cc'] = cc_recipients if cc_recipients else '' msg['Date'] = Utils.formatdate(time()) msg['X-Mailer'] = "CKAN %s" % ckan.__version__ if sender_email: msg['Reply-To'] = Header((u"%s <%s>" % (sender_name, sender_email)), 'utf-8') part = MIMEText(body_html, 'html', 'utf-8') msg.attach(part) if isinstance(file, cgi.FieldStorage): _part = MIMEBase('application', 'octet-stream') _part.set_payload(file.file.read()) Encoders.encode_base64(_part) extension = file.filename.split('.')[-1] header_value = 'attachment; filename=attachment.{0}'.format(extension) _part.add_header('Content-Disposition', header_value) msg.attach(_part) # Send the email using Python's smtplib. smtp_connection = smtplib.SMTP() if 'smtp.test_server' in config: # If 'smtp.test_server' is configured we assume we're running tests, # and don't use the smtp.server, starttls, user, password etc. options. smtp_server = config['smtp.test_server'] smtp_starttls = False smtp_user = None smtp_password = None else: smtp_server = config.get('smtp.server', 'localhost') smtp_starttls = paste.deploy.converters.asbool( config.get('smtp.starttls')) smtp_user = config.get('smtp.user') smtp_password = config.get('smtp.password') smtp_connection.connect(smtp_server) try: # smtp_connection.set_debuglevel(True) # Identify ourselves and prompt the server for supported features. smtp_connection.ehlo() # If 'smtp.starttls' is on in CKAN config, try to put the SMTP # connection into TLS mode. if smtp_starttls: if smtp_connection.has_extn('STARTTLS'): smtp_connection.starttls() # Re-identify ourselves over TLS connection. smtp_connection.ehlo() else: raise MailerException("SMTP server does not support STARTTLS") # If 'smtp.user' is in CKAN config, try to login to SMTP server. if smtp_user: assert smtp_password, ("If smtp.user is configured then " "smtp.password must be configured as well.") smtp_connection.login(smtp_user, smtp_password) smtp_connection.sendmail(mail_from, recipient_email_list, msg.as_string()) log.info("Sent email to provided list of recipients") except smtplib.SMTPException, e: msg = '%r' % e log.exception(msg) raise MailerException(msg)
def encode(self, splitchars=' ', **kwargs): # only split on spaces, rather than splitchars=';, ' return Header.encode(self, splitchars, **kwargs)
def render_POST(self, request): send_cors(request) err, args = get_args(request, ("medium", "address", "room_id", "sender",)) if err: return json.dumps(err) medium = args["medium"] address = args["address"] roomId = args["room_id"] sender = args["sender"] globalAssocStore = GlobalAssociationStore(self.sydent) mxid = globalAssocStore.getMxid(medium, address) if mxid: request.setResponseCode(400) return json.dumps({ "errcode": "THREEPID_IN_USE", "error": "Binding already known", "mxid": mxid, }) if medium != "email": request.setResponseCode(400) return json.dumps({ "errcode": "M_UNRECOGNIZED", "error": "Didn't understand medium '%s'" % (medium,), }) token = self._randomString(128) tokenStore = JoinTokenStore(self.sydent) ephemeralPrivateKey = nacl.signing.SigningKey.generate() ephemeralPublicKey = ephemeralPrivateKey.verify_key ephemeralPrivateKeyBase64 = encode_base64(ephemeralPrivateKey.encode(), True) ephemeralPublicKeyBase64 = encode_base64(ephemeralPublicKey.encode(), True) tokenStore.storeEphemeralPublicKey(ephemeralPublicKeyBase64) tokenStore.storeToken(medium, address, roomId, sender, token) substitutions = {} for key, values in request.args.items(): if len(values) == 1 and type(values[0]) == str: substitutions[key] = values[0] substitutions["token"] = token required = [ 'sender_display_name', 'token', 'room_name', 'bracketed_room_name', 'room_avatar_url', 'sender_display_name', 'guest_user_id', 'guest_access_token', ] for k in required: substitutions.setdefault(k, '') substitutions["ephemeral_private_key"] = ephemeralPrivateKeyBase64 if substitutions["room_name"] != '': substitutions["bracketed_room_name"] = "(%s)" % substitutions["room_name"] subject_header = Header(self.sydent.cfg.get('email', 'email.invite.subject', raw=True) % substitutions, 'utf8') substitutions["subject_header_value"] = subject_header.encode() sendEmail(self.sydent, "email.invite_template", address, substitutions) pubKey = self.sydent.keyring.ed25519.verify_key pubKeyBase64 = encode_base64(pubKey.encode()) baseUrl = "%s/_matrix/identity/api/v1" % (self.sydent.cfg.get('http', 'client_http_base'),) keysToReturn = [] keysToReturn.append({ "public_key": pubKeyBase64, "key_validity_url": baseUrl + "/pubkey/isvalid", }) keysToReturn.append({ "public_key": ephemeralPublicKeyBase64, "key_validity_url": baseUrl + "/pubkey/ephemeral/isvalid", }) resp = { "token": token, "public_key": pubKeyBase64, "public_keys": keysToReturn, "display_name": self.redact(address), } return json.dumps(resp)
def enc_addr_header(name, email): header = Header(name) header.append(email) return header.encode()