def body(self, n): if n not in self.cache['body']: pid, uid, i, _from = self.coda[n] url = "/cp/ps/Mail/commands/LoadMessage?" full_url = url + self.params +'&'+ urllib.urlencode( { 'pid':pid, 'uid':uid, 'an':'DefaultMailAccount', 'fp':'inbox', } ) self.get ( self.baseurl, full_url) url = "/cp/MailMessageBody.jsp?" full_url = url + urllib.urlencode( { 'pid' : pid, 'th' : self.token_hash, } ) _body = self.filter_message( self.get ( self.baseurl, full_url) ) _top = self.top(n) boundary = self.boundary(_top) if boundary: _body = "\r\n\r\n\r\n--" + boundary + "\r\nContent-Type: text/html; charset=UTF-8\r\n"+\ "Content-Transfer-Encoding: quoted-printable\r\n\r\n" + quopri.encodestring(_body.strip(' \r\n')) + \ "\r\n\r\n--" + boundary + "--\r\n" else: _body = "\r\n\r\n" + quopri.encodestring( _body.strip(' \r\n') ) + "\r\n\r\n" self.cache['body'][n] = _body return self.cache['body'][n]
def prepare_message(email, recipient, recipients_list): message = email.message if email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace("<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url)) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, basestring): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join([e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join([e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _("This email was sent to {0} and copied to {1}").format(email_sent_to,email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format(email_sent_to) message = message.replace("<!--cc message-->", quopri.encodestring(email_sent_message)) message = message.replace("<!--recipient-->", recipient) return message
def prepare_message(email, recipient, recipients_list): message = email.message if not message: return "" if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace("<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url.encode()).decode()) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join([e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join([e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _("This email was sent to {0} and copied to {1}").format(email_sent_to,email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format(email_sent_to) message = message.replace("<!--cc message-->", quopri.encodestring(email_sent_message.encode()).decode()) message = message.replace("<!--recipient-->", recipient) message = (message and message.encode('utf8')) or '' if not email.attachments: return message # On-demand attachments from email.parser import Parser msg_obj = Parser().parsestr(message) attachments = json.loads(email.attachments) for attachment in attachments: if attachment.get('fcontent'): continue fid = attachment.get("fid") if fid: fname, fcontent = get_file(fid) attachment.update({ 'fname': fname, 'fcontent': fcontent, 'parent': msg_obj }) attachment.pop("fid", None) add_attachment(**attachment) elif attachment.get("print_format_attachment") == 1: attachment.pop("print_format_attachment", None) print_format_file = frappe.attach_print(**attachment) print_format_file.update({"parent": msg_obj}) add_attachment(**print_format_file) return msg_obj.as_string()
def allow_write_by_path(self, path, userpath, context): logger.debug("allow_write_by_path " + userpath) try: uid, guid, pid = context response = self.send("BEGIN") if not response.startswith("OK"): return True userpathdir, userpathbase = os.path.split(userpath) opid = response.split()[1] response = self.send("SETPROP " + opid + " filename=" + quopri.encodestring(userpathbase)) if not response.startswith("OK"): return True response = self.send("SETPROP " + opid + " destination=" + quopri.encodestring(userpath)) if not response.startswith("OK"): return True response = self.send("SETPROP " + opid + " burn_after_reading=true") if not response.startswith("OK"): return True user_tuple = pwd.getpwuid(uid) username = user_tuple.pw_name response = self.send("SETPROP " + opid + " user="******"OK"): return True response = self.send("PUSHFILE " + opid + " " + quopri.encodestring(path)) if not response.startswith("OK"): return True response = self.send("END " + opid) if not response.startswith("OK"): return True response = self.send("ACLQ " + opid) if not response.startswith("OK"): return True self.send("DESTROY " + opid) print response.split()[1] if response.split()[1] == "block": return False else: return True except (IOError, OSError) as why: logger.error("allow_write_by_path " + str(why) )
def encode_string(encoding, data): encoded = data if encoding == 'base64': encoded = base64.encodestring(data) elif encoding == 'quoted-printable': encoded = quopri.encodestring(data) return encoded
def mimetextpatch(s, subtype='plain', display=False): '''If patch in utf-8 transfer-encode it.''' enc = None for line in s.splitlines(): if len(line) > 950: s = quopri.encodestring(s) enc = "quoted-printable" break cs = 'us-ascii' if not display: try: s.decode('us-ascii') except UnicodeDecodeError: try: s.decode('utf-8') cs = 'utf-8' except UnicodeDecodeError: # We'll go with us-ascii as a fallback. pass msg = email.MIMEText.MIMEText(s, subtype, cs) if enc: del msg['Content-Transfer-Encoding'] msg['Content-Transfer-Encoding'] = enc return msg
def to_quoted_printable(fi): """ Encode selected region into quoted printable text """ offset = fi.getSelectionOffset() length = fi.getSelectionLength() if (length > 0): data = fi.getSelection() orig = list(fi.getDocument()) orig_len = len(orig) encoded = list(quopri.encodestring(data)) final_size = len(encoded) newdata = orig[:offset] newdata.extend(encoded) newdata.extend(orig[offset + length:]) fi.newDocument("New file", 1) fi.setDocument("".join(newdata)) fi.setBookmark(offset, final_size, hex(offset), "#c8ffff") if (length == 1): print "Encoded one byte into quoted printable text from offset %s to %s." % (hex(offset), hex(offset)) else: print "Encoded %s bytes into quoted printable text from offset %s to %s." % (length, hex(offset), hex(offset + length - 1))
def _flatten_bytestring(self, obj): if PY2: try: return obj.decode('utf-8') except: pass return {tags.BYTES: quopri.encodestring(obj).decode('utf-8')}
def encode_string(encoding, data): encoded = data if encoding == "base64": encoded = base64.encodestring(data) elif encoding == "quoted-printable": encoded = quopri.encodestring(data) return encoded.decode("ascii")
def make_replay_response(cls, response): """ Converts real response to replay_response dict which can be saved and/or used to initialize a ReplayHTTPResponse. """ replay_response = {} body = response.read() # undecoded byte string # Add body to replay_response, either as quoted printable for # text responses or base64 for binary responses. if response.getheader('content-type', '') \ .startswith(cls.__text_content_types): if response.getheader('content-encoding') in ['gzip', 'deflate']: # http://stackoverflow.com/questions/2695152 body = zlib.decompress(body, 16 + zlib.MAX_WBITS) del response.msg['content-encoding'] # decompression changes the length if 'content-length' in response.msg: response.msg['content-length'] = str(len(body)) replay_response['body_quoted_printable'] = quopri.encodestring(body) else: replay_response['body'] = body.encode('base64') replay_response.update(dict( status=dict(code=response.status, message=response.reason), headers=dict(response.getheaders()))) return replay_response
def encode_transfer_encoding(encoding, body): if encoding == "quoted-printable": return quopri.encodestring(body) elif encoding == "base64": return base64.b64encode(body) else: return body
def set_body(self, value, content_type): """The the body of the message.""" encode = True if type(value) is unicode: # see if it is plain ascii first try: value = value.encode('us-ascii') encode = False except: value = value.encode('utf-8') content_type += "; charset='utf-8'" else: value = str(value) self['Content-Type'] = content_type if encode: # use the shortest of quoted-printable and base64 encodings qp = quopri.encodestring(value) b64 = base64.b64encode(value) if len(qp) <= len(b64): self.body = qp self['Content-Transfer-Encoding'] = 'quoted-printable' else: self.body = b64 self['Content-Transfer-Encoding'] = 'base64' else: self.body = value
def test_encoding_latin_1_body(self): body = 'I know what you did last '+self.latin_1 self.message.set_payload(body) encoded = self.encode() self.assertTrue(quopri.encodestring(body.encode('latin_1')) in encoded)
def handleOutgoingMail (ctx, mail): #imprime(mail) uri = __aps__['uri'] if uri: found = None for line in mail.head: if line.lower ().startswith ('list-unsubscribe:'): found = line break if found is None: # Tentando extrair link embutido na newsletter if mail.body is not None: soup = BeautifulSoup(quopri.decodestring(mail.body), "html.parser") linkSair = soup.find('a',id='linkUnsubscribe') if linkSair is not None: if linkSair['href'].lower().find("form.do") != -1: novoLink = linkSair['href'] else: # Substituindo link pelo mnemônico, a fim de permitir reconhecimento em alguns leitores de e-mails novoLink = (uri % linkSair['href'][linkSair['href'].lower().find("uid=")+4:]) er = re.compile(r"<a[^<]*linkUnsubscribe.*?>",re.IGNORECASE|re.DOTALL) linkInserido = quopri.decodestring(re.search(er,mail.body).group()) erStyle = re.compile(r"(style=.*?)[a-z].=",re.IGNORECASE|re.DOTALL) styleAdd = re.search(erStyle,linkInserido).group(1) if re.search(erStyle,linkInserido) else "" mail.body = re.sub(er,quopri.encodestring(("<a %s href=%s>" % (styleAdd,novoLink))),mail.body) mail.head.append ('List-Unsubscribe: <%s>' % novoLink) #imprime(mail) return
def build_description(doc, display): desc_part = email.Message.Message() desc_part.set_type("text/html") desc_part.add_header("Content-Transfer-Encoding", "quoted-printable") desc_part.set_payload(quopri.encodestring('<html><body bgcolor="%s">' % STANDARD_BACKGROUND_COLOR + display.encode('UTF-8') + "</body></html>\n"), "UTF-8") return desc_part
def test_encoding_multipart_quopri(self): import quopri from email.mime import multipart from email.mime import nonmultipart from repoze.sendmail._compat import b latin_1_encoded = b('LaPe\xf1a') latin_1 = latin_1_encoded.decode('latin_1') plain_string = 'I know what you did last ' + latin_1 message = multipart.MIMEMultipart('alternative') plain_part = nonmultipart.MIMENonMultipart('plain', 'plain') plain_part.set_payload(plain_string) message.attach(plain_part) html_string = '<p>' + plain_string + '</p>' html_part = nonmultipart.MIMENonMultipart('text', 'html') html_part.set_payload(html_string) message.attach(html_part) encoded = self._callFUT(message) self.assertEqual( encoded.count(quopri.encodestring(plain_string.encode('latin_1'))), 2)
def encode_transfer_encoding(encoding, body): if encoding == 'quoted-printable': return quopri.encodestring(body, quotetabs=False) elif encoding == 'base64': return email.encoders._bencode(body) else: return body
def encode_string(encoding, data): encoded = data if encoding == 'base64': encoded = base64_encodebytes(data).decode('ascii') elif encoding == 'quoted-printable': encoded = quopri.encodestring(data).decode('ascii') return encoded
def encodeKey(key): """ Encode the key like 'Quoted Printable'. """ # According to the memcached's protocol.txt, the key cannot contain # control characters and white spaces. return encodestring(key, True).replace('\n', '').replace('\r', '')
def _encode_quopri(msg): """Own version of quopri isntead of email.encoders.quopri which seems to be buggy in python3""" orig = msg.get_payload() encdata = quopri.encodestring(orig, quotetabs=True) encdata.replace(b' ', b'=20') msg.set_payload(encdata.decode('ascii', 'surrogateescape')) msg['Content-Transfer-Encoding'] = 'quoted-printable'
def saveTweetsToImap(imapapi, twitter_mailbox, new_tweets, myEmailAddress, replyBot, secret, add_excerpt_in_subject): #Instanciate an HTML parser to unescape the tweet text (since we generate a text/plain, this should be safe h = HTMLParser.HTMLParser() for tweet_key in new_tweets: tweet = new_tweets[tweet_key] tweet_id=str(tweet.GetId()) (author, subject, email_text, tweet) = generate_email_elmts(tweet) author_name = preventHeaderInjection(author.GetName()) author_screenname = author.GetScreenName() #Extract hashtags subject_hashtags_suffix = extract_hashtags(tweet) #Extends short links (email_text, links_text) = resolv_short_links(email_text, tweet) #Add tweet excerpt in subject (or not) if add_excerpt_in_subject: subject_excerpt_suffix = " -- " + tweet.GetText()[0:70] if len(subject_excerpt_suffix) >= 74: subject_excerpt_suffix += "..." else: subject_excerpt_suffix="" #merge subject elements and encode it appropriately subject = preventHeaderInjection(subject + subject_hashtags_suffix + subject_excerpt_suffix) quoted_subject = quopri.encodestring(subject.encode('utf-8', 'replace'), quotetabs=True) quoted_subject = quoted_subject.replace("=\n", "").replace("?", "=3F") encoded_subject = "=?utf-8?Q?" + quoted_subject + "?=" #Build security token for retweets and replies securityTokenConstructor = hmac.new(secret); securityTokenConstructor.update(tweet_id) securityToken = securityTokenConstructor.hexdigest() email = "From: " + author_name + " <" + replyBot + ">\n" + \ "To: <" + myEmailAddress + ">\n" + \ "Date: " + time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(tweet.GetCreatedAtInSeconds())) + "\n" + \ "Subject: " + preventHeaderInjection(encoded_subject) + "\n" + \ "Content-Type: text/plain\n" + \ "Content-Encoding: utf-8\n" + \ "TwitterID: " + preventHeaderInjection(tweet_id) + "\n" + \ "\n" + \ h.unescape(email_text) + "\n" + \ "\n\n\n\n\n\n\n" + \ links_text + \ "---------------------------------------------------\n" + \ "SecurityToken=" + securityToken + "\n" + \ "Twitter link= https://twitter.com/" + author_screenname + \ "/status/" + tweet_id + "\n" #Send IMAP cmd to store the tweet imapapi.append(twitter_mailbox, "(New)", tweet.GetCreatedAtInSeconds(), email.encode('utf-8', 'replace'))
def encode(string, encoding): if encoding == "quopri": return quopri.encodestring(string) elif encoding == "base64": return base64.encodestring(string) elif encoding == "raw": return string else: return string
def quote(self, strng): if re.search(self.RE_SHOULD_QUOTE, strng): enc = quopri.encodestring(strng.encode('utf-8'), False, header=True) enc = enc.replace('<', '=3C').replace('>', '=3E') enc = enc.replace(',', '=2C') return '=?utf-8?Q?%s?=' % enc else: return '"%s"' % self.escape(strng)
def encode_quopri(msg): """Same as encoders.encode_quopri except that spaces are kept when possible and end of lines are converted to CRLF ("\r\n") when necessary. """ orig = msg.get_payload() encdata = quopri.encodestring(orig).replace("=\n", "=\r\n") msg.set_payload(encdata) msg.add_header("Content-Transfer-Encoding", "quoted-printable")
def test_attachment_quoted_printable(self): soledad = mock() bdoc = mock() bdoc.content = {'raw': quopri.encodestring('esse papo seu ta qualquer coisa'), 'content-type': 'text/plain'} when(soledad).get_from_index('by-type-and-payloadhash', 'cnt', any(unicode)).thenReturn([bdoc]) querier = SoledadQuerier(soledad) attachment = querier.attachment(u'0400BEBACAFE', 'quoted-printable') self.assertEquals('esse papo seu ta qualquer coisa', attachment['content'])
def keyToQuo(key, joi='\n\n'): """Returns a quoted printable version of a key - ee then m. Leading and trailing whitespace is allowed; stripped by quoToKey.""" e, n = str(key.e), str(key.n) # Convert the ee and mod to strings if key.has_private(): d, p, q = str(key.d), str(key.p), str(key.q) strkey = base64.encodestring(joi.join([e, n, d, p, q])) else: strkey = base64.encodestring('%s%s%s' % (e, joi, n)) return '\n'+quopri.encodestring(strkey).strip()+'\n'
def test_7bit_text(): msg = DraftMessage( from_addr=addr_arg('*****@*****.**'), to_addrs=[addr_arg('*****@*****.**')], subject='test_7bit_text', ) msg.addtext(TEXT) blob = bytes(msg.compile()) assert isinstance(blob, bytes) assert TEXT_ENC not in blob assert quopri.encodestring(TEXT_ENC) in blob or b64encode(TEXT_ENC) in blob
def q_encode(s, enc): # perform quoted-printable encoding s = quopri.encodestring(s); # encode invalid characters ('?' and '_') and the space substitutions = {'\?': '=3F', '_': '=5F', ' ': '_'}; for symbol, sub in substitutions.iteritems(): pat = re.compile(symbol); s = pat.sub(sub, s); # return q-encoded title out = "=?%s?Q?%s?=" % (enc, s); return out;
def q_encode(s, enc): # perform quoted-printable encoding s = quopri.encodestring(as_bytes(s)) # encode invalid characters ('?' and '_') and the space substitutions = {b'\?': b'=3F', b'_': b'=5F', b' ': b'_'} for symbol, sub in substitutions.items(): pat = re.compile(symbol) s = pat.sub(sub, s) # return q-encoded title out = "=?%s?Q?%s?=" % (enc, as_str(s)) return out
def getSearchMailList(self, foldername, criterion, keyword_, begin, end): keyword = "" if (keyword_ != None): keyword = quopri.encodestring(keyword_) self.response = [] select_response = self.imap.select(imapUTF7Encode(foldername.decode("utf8")), True) if (select_response[0] != "OK"): self.error = commons.error.IMAP_SELECT return False if (criterion == "ALL"): query = '(ALL)' elif (criterion == "RECENT"): query = '(UNSEEN)' elif (criterion == "SUBJECT"): query = '(SUBJECT ' + keyword + ')' elif (criterion == "FROM"): query = '(FROM ' + keyword + ')' elif (criterion == "SUBJECT_OR_FROM"): query = '(OR SUBJECT ' + keyword + ' FROM ' + keyword + ')' elif (criterion == "TO_OR_CC"): query = '(OR TO ' + keyword + ' CC ' + keyword + ')' else: query = '(BODY ' + keyword + ')' search_response = self.imap.search(None, query) if (search_response[0] != "OK"): self.error = commons.error.IMAP_SEARCH return False if (search_response[1][0] == ""): # No hay mensajes return True message_list = search_response[1][0].split(" ") self.size = len(message_list) message_list.reverse() fetch_response = self.imap.fetch(",".join([str(i) for i in message_list[(begin-1):end]]), "(UID RFC822.SIZE FLAGS BODY[HEADER.FIELDS (DATE FROM TO CC BCC SUBJECT CONTENT-TYPE)])") if (fetch_response[0] != "OK"): self.error = commons.error.IMAP_FETCH return False fetch_response[1].reverse() for i in range(len(fetch_response[1])): if fetch_response[1][i].__class__ == ().__class__: msg = parseMailHeader(fetch_response[1][i]) self.response.append(msg) return True
def add_html(self, content): content = content.encode('utf-8') encoded = quopri.encodestring(content) self.set_payload(encoded, charset='utf-8')
def stop_email(self): success = False smtp = smtplib.SMTP(self.email_host, self.email_port) self.email_body = self.email_body + "</body></html>" useMime = False if len(self.email_figlist) > 0: useMime = True mime_boundary = "pymanip-MIME-delimiter" if useMime: email_header = ( 'Content-type: multipart/mixed; boundary="' + mime_boundary + '"\n' ) email_header = email_header + "MIME-version: 1.0\n" else: email_header = "Content-Type: text/html\n" email_header = ( email_header + "Content-Transfer-Encoding: quoted-printable\n" ) email_header = email_header + "User-Agent: pymanip\n" email_header = email_header + "To: " if isinstance(self.email_to_addrs, str): email_header = email_header + self.email_to_addrs + "\n" elif isinstance(self.email_to_addrs, tuple): for addr in self.email_to_addrs[:-1]: email_header = email_header + addr + ", " email_header = email_header + self.email_to_addrs[-1] + "\n" else: raise ValueError("Adress list should be a string or a tuple") email_header = email_header + "Subject: " + self.email_subject if useMime: body = "This is a multi-part message in MIME format.\n" # Add text/html MIME part body = body + "--" + mime_boundary + "\n" body = body + "Content-Type: text/html; charset=UTF-8\n" body = body + "Content-Transfer-Encoding: quoted-printable\n\n" body = ( body + quopri.encodestring(self.email_body.encode("utf-8")).decode("utf-8") + "\n" ) # Add figures for fig in self.email_figlist: plt.figure(fig) (fd, fname) = tempfile.mkstemp(suffix=".png") f_png = os.fdopen(fd, "wb") plt.savefig(f_png) f_png.close() with open(fname, "rb") as image_file: encoded_figure = base64.b64encode(image_file.read()).decode("ascii") os.remove(fname) # Add image/png MIME part body = body + "--" + mime_boundary + "\n" body = body + "Content-Type: image/png\n" body = body + "Content-Disposition: inline\n" body = body + "Content-Transfer-Encoding: base64\n\n" for i in range(0, len(encoded_figure), 76): debut = i fin = i + 75 if fin >= len(encoded_figure): fin = len(encoded_figure) - 1 body = body + encoded_figure[debut : (fin + 1)] + "\n" # Send email try: error_list = smtp.sendmail( self.email_from_addr, self.email_to_addrs, email_header + "\n" + body + "\n" + "--" + mime_boundary + "--\n", ) if len(error_list) == 0: success = True except smtplib.SMTPHeloError: print("SMTP Helo Error") pass except smtplib.SMTPRecipientsRefused: print("Some recipients have been rejected by SMTP server") pass except smtplib.SMTPSenderRefused: print("SMTP server refused sender " + self.email_from_addr) pass except smtplib.SMTPDataError: print("SMTP Data Error") pass else: try: email_content = ( email_header.encode("utf-8") + b"\n" + quopri.encodestring(self.email_body.encode("utf-8")) ) error_list = smtp.sendmail( self.email_from_addr, self.email_to_addrs, email_content ) if len(error_list) == 0: success = True except smtplib.SMTPHeloError: print("SMTP Helo Error") pass except smtplib.SMTPRecipientsRefused: print("Some recipients have been rejected by SMTP server") pass except smtplib.SMTPSenderRefused: print("SMTP server refused sender " + self.email_from_addr) pass except smtplib.SMTPDataError: print("SMTP Data Error") pass smtp.quit() self.email_body = "" self.email_started = False self.email_figlist = [] if success: self.parameters["email_lastSent"] = time.time() date_string = time.strftime( dateformat, time.localtime(self.parameters["email_lastSent"]) ) print(date_string + ": Email successfully sent.")
def test_encodestring(self): for p, e in self.STRINGS: self.assertEqual(quopri.encodestring(p), e)
def esc(s): return quopri.encodestring(s, quotetabs=True)
def ascii_token(text): """Turn a text (unicode in Py2, str in Py3) into a ASCII-only bytestring that is safe to use in term tokens. """ return quopri.encodestring(text.encode('utf-8'))
def _escape_mime(s): return '=?utf-8?Q?' + (b''.join( bytes((b, )) if b >= 0x20 else b'=%02X' % b for b in quopri.encodestring(s.encode('utf-8'), header=True)) ).decode('us-ascii') + '?='
def test_idempotent_string(self): for p, e in self.STRINGS: self.assertTrue(quopri.decodestring(quopri.encodestring(e)) == e)
def main(): """Convert MHT file given as command line argument (or stdin?) to files and directories in the current directory. Usage: cd foo-unpacked/ mht2fs.py ../foo.mht """ parser = argparse.ArgumentParser( description="Extract MHT archive into new directory.") parser.add_argument("mht", metavar="MHT", help='path to MHT file, use "-" for stdin/stdout.') parser.add_argument( "d", metavar="DIR", help="directory to create to store parts in, or read them from." ) #??? How to make optional, default to current dir? parser.add_argument("-p", "--pack", action="store_true", help="pack file under DIR into an MHT.") parser.add_argument("-u", "--unpack", action="store_true", help="unpack MHT into a new DIR.") parser.add_argument("-v", "--verbose", action="store_true") parser.add_argument("-q", "--quiet", action="store_true") args = parser.parse_args() # --help is built-in. # Validate command line. if args.pack == args.unpack: sys.stderr.write( "Invalid: must specify one action, either --pack or --unpack.\n") sys.exit(-1) # File name or stdin/stdout? if args.mht == "-": mht = sys.stdout if args.pack else sys.stdin.buffer else: if args.pack and os.path.exists(args.mht): # Refuse to overwrite MHT file. sys.stderr.write("Error: MHT file exists, won't overwrite.\n") sys.exit(-2) mht = open(args.mht, "wb" if args.pack else "rb") # New directory? if args.unpack: os.mkdir(args.d) # Change directory so paths (content-location) are relative to index.html. os.chdir(args.d) # Un/pack? if args.unpack: if not args.quiet: sys.stderr.write("Unpacking...\n") # Read entire MHT archive -- it's a multipart(/related) message. a = email.message_from_bytes( mht.read() ) # Parser is "conducive to incremental parsing of email messages, such as would be necessary when reading the text of an email message from a source that can block", so I guess it's more efficient to have it read stdin directly, rather than buffering. if type(a.get_payload()) is list: parts = a.get_payload() # multiple parts are given else: parts = [a] # single 'str' part is given # Save all parts to files. for p in parts: # walk() for a tree, but I'm guessing MHT is never nested? #??? cs = p.get_charset() # Expecting "utf-8" for root HTML, None for all other parts. ct = p.get_content_type( ) # String coerced to lower case of the form maintype/subtype, else get_default_type(). fp = p.get( "content-location" ) or "index.html" # File path. Expecting root HTML is only part with no location. if args.verbose: sys.stderr.write("Writing %s to %s, %d bytes...\n" % (ct, fp, len(p.get_payload()))) # Create directories as necessary. if os.path.dirname(fp): os.makedirs(os.path.dirname(fp), exist_ok=True) # Save part's body to a file. open(fp, "wb").write(p.get_payload(decode=True)) if not args.quiet: sys.stderr.write("Done.\nUnpacked %d files.\n" % (len(parts))) else: if not args.quiet: sys.stderr.write("Packing...\n") # Create archive as multipart message. a = email.message.Message() a["MIME-Version"] = "1.0" a.add_header("Content-Type", "multipart/related", type="text/html") # Walk current directory. for (root, _, files) in os.walk("."): # Create message part from each file and attach them to archive. for f in files: p = os.path.join(root, f).lstrip("./") m = email.message.Message() # Encode and set type of part. t = mimetypes.guess_type(f)[0] if t: m["Content-Type"] = t if args.verbose: sys.stderr.write("Reading %s as %s...\n" % (p, t)) if t and t.startswith("text/"): m["Content-Transfer-Encoding"] = "quoted-printable" m.set_payload( quopri.encodestring( open(p, "rt").read().encode("utf-8")).decode( "ascii")) #??? WTF? else: m["Content-Transfer-Encoding"] = "base64" m.set_payload( base64.b64encode(open(p, "rb").read()).decode("ascii")) #??? My editor, Geany, suffocates, I think, when needs to wrap these long lines? # Only set charset for index.html to UTF-8, and no location. if f == "index.html": m.add_header("Content-Type", "text/html", charset="utf-8") #??? m.set_charset("utf-8") else: m["Content-Location"] = p a.attach(m) # Write MHT file. #??? verify index.html is present!? mht.write( bytes(a.as_string(unixfrom=False), "utf-8") ) # Not an mbox file, so we don't need to mangle "From " lines, I guess? if not args.quiet: sys.stderr.write("Done.\nPacked %d files.\n" % (len(a.get_payload())))
def to_quopri(msg): return quopri.encodestring(msg.encode()).decode()
def set_part_payload(part, content_type, content): part.add_header('Content-Type', content_type, charset='utf-8') part['Content-Transfer-Encoding'] = 'quoted-printable' part.set_payload(quopri.encodestring(content.encode('utf-8')))
def encode(self, text): return quopri.encodestring(bytes(text, ENC)).decode(ENC)
def quoted_printable(self): """ Return contents encoded as quoted-printable. """ return quopri.encodestring(self.__text).decode('ascii')
def thg_encode(self, args): """modulo referente a encode de estrings""" arg_mensage = args.split(" ") if arg_mensage[0] == "": print("""suporte encode: Este módulo fornece funções para codificar dados binários em caracteres ASCII imprimÃveis e decodificar essas codificações de volta para dados binários. Ele fornece funções de codificação e decodificação para as codificações especificadas em RFC 3548 ,que define os algoritmos Base16, Base32 e Base64, e para as codificações Ascii85 e Base85 padrão de fato. a2b_uu b2a_uu a2b_base64 b2a_base64 a2b_qp b2a_qp a2b_hqx rledecode_hqx rlecode_hqx b2a_hqx crc_hqx crc32 b2a_hex a2b_hex hexlify unhexlify Charcode binary base62 basen bcd ur unicode_normalize qp_encoding encode type[2,16,32,64] str """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) elif arg_mensage[0] == "64": arg_mensage[1] = arg_mensage[1].encode("ascii") base64_bytes = base64.b64encode(arg_mensage[1]) by_to_st(base64_bytes) elif arg_mensage[0] == "32": arg_mensage[1] = arg_mensage[1].encode("ascii") b32encode_bytes = base64.b32encode(arg_mensage[1]) by_to_st(b32encode_bytes) elif arg_mensage[0] == "16": arg_mensage[1] = arg_mensage[1].encode("ascii") b16encode_bytes = base64.b16encode(arg_mensage[1]) by_to_st(b16encode_bytes) elif arg_mensage[0] == "a85encode": arg_mensage[1] = arg_mensage[1].encode("ascii") a85encode_bytes = base64.a85encode(arg_mensage[1]) by_to_st(a85encode_bytes) elif arg_mensage[0] == "b85encode": arg_mensage[1] = arg_mensage[1].encode("ascii") b85encode_bytes = base64.b85encode(arg_mensage[1]) by_to_st(b85encode_bytes) elif arg_mensage[0] == "a2b_uu": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Converta uma única linha de dados uuencodificados de volta em binários e retorne os dados binários. As linhas normalmente contêm 45 bytes (binários), exceto a última linha. Os dados da linha podem ser seguidos de espaços em branco.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.a2b_uu(arg_mensage[1]))) elif arg_mensage[0] == "a2b_base64": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED}Converta dados binários em uma linha de caracteres ASCII na codificação base64. O valor de retorno é a linha convertida, incluindo um caractere de nova linha. O comprimento dos dados deve ser de no máximo 57 para aderir ao padrão base64.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st(binascii.a2b_base64(arg_mensage[1])) elif arg_mensage[0] == "b2a_base64": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Converta dados binários em uma linha de caracteres ASCII na codificação base64. O valor de retorno é a linha convertida, incluindo um caractere de nova linha. O comprimento dos dados deve ser de no máximo 57 para aderir ao padrão base64.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st(binascii.b2a_base64(b"arg_mensage[1]")) elif arg_mensage[0] == "a2b_qp": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED}Converta um bloco de dados imprimÃveis entre aspas de volta em binários e retorne os dados binários. Mais de uma linha pode ser passada por vez. Se o cabeçalho do argumento opcional estiver presente e verdadeiro, os sublinhados serão decodificados como espaços.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st(binascii.a2b_qp(arg_mensage[1])) elif arg_mensage[0] == "b2a_qp": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED}Converta dados binários em uma (s) linha (s) de caracteres ASCII em codificação imprimÃvel entre aspas. O valor de retorno é a (s) linha (s) convertida (s). Se o argumento opcional quotetabs estiver presente e verdadeiro, todas as tabulações e espaços serão codificados. Se o argumento opcional istext estiver presente e verdadeiro, as novas linhas não serão codificadas, mas os espaços em branco finais serão codificados. Se o cabeçalho do argumento opcional estiver presente e verdadeiro, os espaços serão codificados como sublinhados de acordo com RFC1522. Se o cabeçalho do argumento opcional estiver presente e for falso, os caracteres de nova linha também serão codificados; caso contrário, a conversão de alimentação de linha pode corromper o fluxo de dados binários.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st(binascii.a2b_qp(arg_mensage[1].encode())) elif arg_mensage[0] == "a2b_hqx": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED}Converta dados ASCII formatados de binhex4 em binários, sem fazer a descompressão RLE. A string deve conter um número completo de bytes binários ou (no caso da última parte dos dados binhex4) ter os bits restantes zero. """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st(binascii.a2b_hqx(arg_mensage[1])) elif arg_mensage[0] == "rledecode_hqx": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Execute a descompressão RLE nos dados, de acordo com o padrão binhex4. O algoritmo usa 0x90 após um byte como um indicador de repetição, seguido por uma contagem. Uma contagem de 0 especifica um valor de byte de 0x90 . A rotina retorna os dados descompactados, a menos que os dados de entrada de dados terminem em um indicador de repetição órfão, caso em que a exceção Incompleta é levantada.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.rledecode_hqx(arg_mensage[1].encode()))) elif arg_mensage[0] == "rlecode_hqx": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Execute a compactação RLE no estilo binhex4 nos dados e retorne o resultado.""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.rlecode_hqx(arg_mensage[1].encode()))) elif arg_mensage[0] == "b2a_hqx": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Execute a conversão hexbin4 binário para ASCII e retorne a string resultante. O argumento já deve ser codificado por RLE e ter um comprimento divisÃvel por 3 (exceto possivelmente o último fragmento). """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.b2a_hqx(arg_mensage[1].encode()))) elif arg_mensage[0] == "crc_hqx": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Calcule o valor binhex4 crc dos dados , começando com um crc inicial e retornando o resultado. """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.crc_hqx(arg_mensage[1].encode(), int(arg_mensage[2])))) elif arg_mensage[0] == "crc32": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Calcule CRC-32, a soma de verificação de dados de 32 bits, começando com um crc inicial. Isso é consistente com a soma de verificação do arquivo ZIP. Uma vez que o algoritmo é projetado para uso como um algoritmo de soma de verificação, não é adequado para uso como um algoritmo de hash geral. {YELLOW}Nota{YELLOW}{RED} Para gerar o mesmo valor numérico em todas as versões e plataformas Python, {RED}{BLUE}use crc32 (dados) & 0xffffffff{BLUE}{RED}. Se você estiver usando apenas a soma de verificação no formato binário compactado, isso não é necessário, pois o valor de retorno é a representação binária correta de 32 bits, independentemente do sinal. """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.crc32(arg_mensage[1].encode()))) elif arg_mensage[0] == "hexlify": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Retorna a representação hexadecimal dos dados binários . Cada byte de dados é convertido na representação hexadecimal de 2 dÃgitos correspondente. A string resultante é, portanto, o dobro do comprimento dos dados . """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.hexlify(arg_mensage[1].encode(), arg_mensage[2].encode()))) elif arg_mensage[0] == "b2a_hex": if arg_mensage[1] == "help": print("""{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} hex """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.b2a_hex(arg_mensage[1].encode(), int(arg_mensage[2])))) elif arg_mensage[0] == "unhexlify": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Retorna os dados binários representados pela string hexadecimal hexstr . Esta função é o inverso de b2a_hex () . hexstr deve conter um número par de dÃgitos hexadecimais (que podem ser maiúsculas ou minúsculas), caso contrário, um TypeError é gerado. """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.unhexlify(arg_mensage[1].encode()))) elif arg_mensage[0] == "b2a_uu": if arg_mensage[1] == "help": print( """{YELLOW}a2b_uu{YELLOW}{BLUE} =>{BLUE}{RED} Converta dados binários em uma linha de caracteres ASCII, o valor de retorno é a linha convertida, incluindo um caractere de nova linha. O comprimento dos dados deve ser de no máximo 45. """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: by_to_st((binascii.b2a_uu(arg_mensage[1].encode(), int(arg_mensage[2])))) elif arg_mensage[0] == "charcode": if arg_mensage[1] == "help": print( """{YELLOW}charcode{YELLOW}{BLUE} =>{BLUE}{RED}converte string em charcode """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print(ord(arg_mensage[1].encode())) elif arg_mensage[0] == "binary": if arg_mensage[1] == "help": print( """{YELLOW}binary{YELLOW}{BLUE} =>{BLUE}{RED}converte string em binary """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print(" ".join( format(ord(x), "b") for x in arg_mensage[1])) elif arg_mensage[0] == "base62": if arg_mensage[1] == "help": print( """{YELLOW}base62{YELLOW}{BLUE} =>{BLUE}{RED}converte string em base62 """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print(decode62(arg_mensage[1])) elif arg_mensage[0] == "basen": if arg_mensage[1] == "help": print( """{YELLOW}basen{YELLOW}{BLUE} =>{BLUE}{RED}converte decimal em basen """.format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print( numpy.base_repr(int(arg_mensage[1]), base=int(arg_mensage[2]))) elif arg_mensage[0] == "url": try: if arg_mensage[1] == "help": print( """{YELLOW}url_encode{YELLOW}{BLUE} =>{BLUE}{RED}encode personalidado para url\nencode url_encode safa[] encoding""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print( quote(arg_mensage[1], safe=arg_mensage[2], encoding=arg_mensage[3])) except IndexError: print( "digite a sintaxe correta\nncode url_encode safa[] encoding\n ou use o comando help" ) elif arg_mensage[0] == "unicode_normalize": try: if arg_mensage[1] == "help": print( """{YELLOW}unicode_normalize{YELLOW}{BLUE} =>{BLUE}{RED}Transforme caracteres Unicode em uma das formas de normalização['NFC', 'NFKC', 'NFD','NFKD']\n {YELLOW}NFD{YELLOW}{BLUE} =>{BLUE}{RED}Normalisation Form Canonical Decomposition {YELLOW}NFC{YELLOW}{BLUE} =>{BLUE}{RED}Normalisation Form Canonical Composition {YELLOW}NFKD{YELLOW}{BLUE} =>{BLUE}{RED}Normalisation Form Compatibility Decomposition {YELLOW}NFKC{YELLOW}{BLUE} =>{BLUE}{RED}Normalisation Form Compatibility Composition encode unicode_normalize str encoding['NFC', 'NFKC', 'NFD','NFKD']\n""". format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print( unicodedata.normalize(arg_mensage[1], arg_mensage[2])) except IndexError: print( "digite a sintaxe correta\nncode url_encode safa[] encoding\n ou use o comando help" ) elif arg_mensage[0] == "qp_encoding": try: if arg_mensage[1] == "help": print( """{YELLOW}qp_encoding{YELLOW}{BLUE} =>{BLUE}{RED} Quoted-Printable, ou QP encoding, é uma codificação que usa caracteres ASCII imprimÃveis (alfanuméricos e o sinal de igual '=') para transmitir dados de 8 bits em um caminho de dados de 7 bits ou, geralmente, em um meio que não é 8- um pouco limpo. É definido como uma codificação de transferência de conteúdo MIME para uso em e-mail. QP funciona usando o sinal de igual '=' como um caractere de escape. Ele também limita o comprimento da linha a 76, pois alguns softwares têm limites no comprimento da linha\nencode qp_encoding TXT encode""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: encoded = quopri.encodestring(arg_mensage[1].encode( arg_mensage[2])) print(encoded.decode()) except IndexError: print( "digite a sintaxe correta\nencode qp_encoding é utf-16\n ou use o comando help" ) elif arg_mensage[0] == "idna": try: if arg_mensage[1] == "help": print( """{YELLOW}idna{YELLOW}{BLUE} =>{BLUE}{RED}encode personalidado para url\nencode url_encode safa[] encoding""" .format(YELLOW=Fore.YELLOW, BLUE=Fore.BLUE, RED=Fore.RED)) else: print( idna.encode(arg_mensage[1]).decode(arg_mensage[2])) except IndexError: print( "digite a sintaxe correta\nncode idna string encoding\n ou use o comando help" ) else: pass try: pass except IndexError: print("verificar a saida")
def encode_quopri(msg): orig = msg.get_payload() encdata = quopri.encodestring(orig) msg.set_payload(encdata) del msg['Content-Transfer-Encoding'] msg['Content-Transfer-Encoding'] = 'quoted-printable'
def test_encode_header(self): for p, e in self.HSTRINGS: self.assertEqual(quopri.encodestring(p, header=True), e)
def encode_unix(value): return quopri.encodestring(value).decode('utf8')
def test_encodestring(self): for p, e in self.STRINGS: self.assert_(quopri.encodestring(p) == e)
def test_embedded_ws(self): for p, e in self.ESTRINGS: self.assertEqual(quopri.encodestring(p, quotetabs=True), e) self.assertEqual(quopri.decodestring(e), p)
def test_verify(self): signed_msg = sign(MSG, TEST_CERT_FILE, TEST_KEY_FILE) # This is a manual 'fudge' to make MS2 appear like a # quoted-printable message when signed # Encode MSG2 so it's 'quoted-printable', after encoding it to ensure # it's a bytes object for Python 3. Latter is a no-op in Python 2. quopri_msg = quopri.encodestring(MSG2.encode()) # In Python 3, encodestring() returns bytes so decode to a string while # Python 2 compatability is still required. if not isinstance(quopri_msg, str): quopri_msg = quopri_msg.decode() # Add Content-Type and Content-Transfer-Encoding # headers to message header_quopri_msg = ('Content-Type: text/xml; charset=utf8\n' 'Content-Transfer-Encoding: quoted-printable\n' '\n' '%s' % quopri_msg) # We can't use crypto.sign as that assumes the use of the '-text' option # which cause the message to be interpreted as plaintext p1 = Popen([ 'openssl', 'smime', '-sign', '-inkey', TEST_KEY_FILE, '-signer', TEST_CERT_FILE ], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) signed_msg2, error = p1.communicate(header_quopri_msg) if error != '': self.fail(error) retrieved_msg, retrieved_dn = verify(signed_msg, TEST_CA_DIR, False) if not retrieved_dn == TEST_CERT_DN: self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg.strip() == MSG: self.fail("The verified messge didn't match the original.") retrieved_msg2, retrieved_dn2 = verify(signed_msg2, TEST_CA_DIR, False) if not retrieved_dn2 == TEST_CERT_DN: print(retrieved_dn2) print(TEST_CERT_DN) self.fail("The DN of the verified message didn't match the cert.") if not retrieved_msg2.strip() == MSG2: print(retrieved_msg2) print(MSG2) self.fail("The verified messge didn't match the original.") # Try empty string try: verify('', TEST_CA_DIR, False) except CryptoException: pass # Try rubbish try: verify('Bibbly bobbly', TEST_CA_DIR, False) except CryptoException: pass # Try None arguments try: verify('Bibbly bobbly', None, False) except CryptoException: pass try: verify(None, 'not a path', False) except CryptoException: pass
def test_idempotent_string(self): for p, e in self.STRINGS: self.assertEqual(quopri.decodestring(quopri.encodestring(e)), e)
def send_email(self, message, customizations=None): md = markdown.Markdown() if isinstance(customizations, dict): from_address = customizations.get('from', self.config['from']) else: from_address = self.config['from'] start = time.time() m = MIMEMultipart('alternative') priority = message.get('priority') if priority: m['X-IRIS-PRIORITY'] = priority application = message.get('application') if application: m['X-IRIS-APPLICATION'] = application plan = message.get('plan') if plan: m['X-IRIS-PLAN'] = plan incident_id = message.get('incident_id') if incident_id: m['X-IRIS-INCIDENT-ID'] = str(incident_id) m['Date'] = formatdate(localtime=True) m['from'] = from_address m['to'] = message['destination'] if message.get('noreply'): m['reply-to'] = m['to'] if 'email_subject' in message: m['subject'] = message['email_subject'] else: m['subject'] = message['subject'] plaintext = None if 'email_text' in message: plaintext = message['email_text'] elif 'body' in message: plaintext = message['body'] if plaintext: mt = MIMEText(None, 'plain', 'utf-8') mt.set_payload(quopri.encodestring(plaintext.encode('UTF-8'))) mt.replace_header('Content-Transfer-Encoding', 'quoted-printable') m.attach(mt) # for tracking messages, email_html is not required, so it's possible # that both of the following keys are missing from message html = None if 'email_html' in message: html = message['email_html'] elif 'body' in message: html = md.convert(message['body']) if html: if 'extra_html' in message: html += message['extra_html'] # We need to have body tags for the oneclick buttons to properly parse html = '<body>\n' + html + '\n</body>' mt = MIMEText(None, 'html', 'utf-8') # Google does not like base64 encoded emails for the oneclick button functionalty, # so force quoted printable. mt.set_payload(quopri.encodestring(html.encode('UTF-8'))) mt.replace_header('Content-Transfer-Encoding', 'quoted-printable') m.attach(mt) conn = None # Try reusing previous connection in this worker if we have one if self.last_conn: conn = self.last_conn else: for mx in self.mx_sorted: try: smtp = SMTP(timeout=self.smtp_timeout) smtp.connect(mx[1], self.config.get('port', 25)) if self.config.get('username', None) is not None and self.config.get( 'password', None) is not None: smtp.login(self.config.get('username', None), self.config.get('password', None)) conn = smtp self.last_conn = conn self.last_conn_server = mx[1] break except Exception as e: logger.exception(e) if not conn: raise Exception('Failed to get smtp connection.') try: conn.sendmail([from_address], [message['destination']], m.as_string()) except Exception: logger.warning( 'Failed sending email through %s. Will try connecting again and resending.', self.last_conn_server) try: conn.quit() except Exception: pass # If we can't send it, try reconnecting and then sending it one more time before # giving up for mx in self.mx_sorted: try: smtp = SMTP(timeout=self.smtp_timeout) smtp.connect(mx[1], 25) conn = smtp self.last_conn = conn self.last_conn_server = mx[1] break except Exception as e: logger.exception( 'Failed reconnecting to %s to send message', self.last_conn_server) self.last_conn = None return None try: # If configured, sleep to back-off on connection if self.retry_interval: sleep(self.retry_interval) conn.sendmail([from_address], [message['destination']], m.as_string()) logger.info( 'Message successfully sent through %s after reconnecting', self.last_conn_server) except Exception: logger.exception( 'Failed sending email through %s after trying to reconnect', self.last_conn_server) return None return time.time() - start
innerId = '_001_' + msgId message += 'Content-Type: multipart/related;\r\n\tboundary="===============' + innerId + '==";\r\n\t' message += 'type="multipart/alternative"\r\n\r\n' #Add boundary for msg innerMsgId = '_002_' + msgId message += '--===============' + innerId + '==\r\n' message += 'Content-Type: multipart/alternative;\r\n\tboundary="===============' + innerMsgId + '=="\r\n\r\n' #Add plain text if specified if args.plain_content: f = open(args.plain_content, 'rb') inner_body = f.read() f.close() #Quote encode inner_body = quopri.encodestring(inner_body) #Add inner msg boundary id if innerMsgId != outerId: message += '--===============' + innerMsgId + '==\r\n' #Add the plain message message += 'Content-Type: text/plain; charset="us-ascii"\r\n' message += 'Content-Transfer-Encoding: quoted-printable\r\n\r\n' message += inner_body + '\r\n\r\n' #Read msg file if args.html_content: f = open(args.html_content, 'rb') inner_body = f.read()
#coding=utf-8 #version 1.0 import quopri import sys if sys.platform=='linux': import readline if len(sys.argv)==2: s=sys.argv[1] print() print(str(quopri.encodestring(s.encode('utf-8')),encoding='utf-8')) print() exit() while True: q=input('input str>') if q=='exit()': exit() elif q=='': continue print(str(quopri.encodestring(q.encode('utf-8')),encoding='utf-8'))
def prepare_message(email, recipient, recipients_list): message = email.message if not message: return "" # Parse "Email Account" from "Email Sender" email_account = get_outgoing_email_account(raise_exception_not_set=False, sender=email.sender) if frappe.conf.use_ssl and email_account.track_email_status: # Using SSL => Publically available domain => Email Read Reciept Possible message = message.replace( "<!--email open check-->", quopri.encodestring( '<img src="https://{}/api/method/frappe.core.doctype.communication.email.mark_email_as_seen?name={}"/>' .format(frappe.local.site, email.communication).encode()).decode()) else: # No SSL => No Email Read Reciept message = message.replace("<!--email open check-->", quopri.encodestring("".encode()).decode()) if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace( "<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url.encode()).decode()) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join( [e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join( [e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _( "This email was sent to {0} and copied to {1}").format( email_sent_to, email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format( email_sent_to) message = message.replace( "<!--cc message-->", quopri.encodestring(email_sent_message.encode()).decode()) message = message.replace("<!--recipient-->", recipient) message = (message and message.encode('utf8')) or '' message = safe_decode(message) if not email.attachments: return message # On-demand attachments from email.parser import Parser msg_obj = Parser().parsestr(message) attachments = json.loads(email.attachments) for attachment in attachments: if attachment.get('fcontent'): continue fid = attachment.get("fid") if fid: fname, fcontent = get_file(fid) attachment.update({ 'fname': fname, 'fcontent': fcontent, 'parent': msg_obj }) attachment.pop("fid", None) add_attachment(**attachment) elif attachment.get("print_format_attachment") == 1: attachment.pop("print_format_attachment", None) print_format_file = frappe.attach_print(**attachment) print_format_file.update({"parent": msg_obj}) add_attachment(**print_format_file) return msg_obj.as_string()
def prepare_message(email, recipient, recipients_list): message = email.message if not message: return "" if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace( "<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url.encode()).decode()) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join( [e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join( [e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _( "This email was sent to {0} and copied to {1}").format( email_sent_to, email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format( email_sent_to) message = message.replace( "<!--cc message-->", quopri.encodestring(email_sent_message.encode()).decode()) message = message.replace("<!--recipient-->", recipient) message = (message and message.encode('utf8')) or '' if not email.attachments: return message # On-demand attachments from email.parser import Parser msg_obj = Parser().parsestr(message) attachments = json.loads(email.attachments) for attachment in attachments: if attachment.get('fcontent'): continue fid = attachment.get("fid") if fid: fname, fcontent = get_file(fid) attachment.update({ 'fname': fname, 'fcontent': fcontent, 'parent': msg_obj }) attachment.pop("fid", None) add_attachment(**attachment) elif attachment.get("print_format_attachment") == 1: attachment.pop("print_format_attachment", None) print_format_file = frappe.attach_print(**attachment) print_format_file.update({"parent": msg_obj}) add_attachment(**print_format_file) return msg_obj.as_string()
def encode_unix(value): return quopri.encodestring(value)
def myqpencodestring(value): """My own routine to do qouted printable since the builtin one doesn't encode CR or NL!""" return quopri.encodestring(value).replace("\r", "=0D").replace("\n", "=0A")
def _qencode(s): enc = quopri.encodestring(s, quotetabs=True) # Must encode spaces, which quopri.encodestring() doesn't do return enc.replace(b' ', b'=20')