def test_cte_type_7bit_transforms_8bit_cte(self): source = textwrap.dedent("""\ From: [email protected] To: Dinsdale Subject: Nudge nudge, wink, wink Mime-Version: 1.0 Content-Type: text/plain; charset="latin-1" Content-Transfer-Encoding: 8bit oh là là, know what I mean, know what I mean? """).encode('latin1') msg = message_from_bytes(source) expected = textwrap.dedent("""\ From: [email protected] To: Dinsdale Subject: Nudge nudge, wink, wink Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable oh l=E0 l=E0, know what I mean, know what I mean? """).encode('ascii') s = io.BytesIO() g = BytesGenerator(s, policy=self.policy.clone(cte_type='7bit', linesep='\n')) g.flatten(msg) self.assertEqual(s.getvalue(), expected)
def createMessage(self, entry=None): """ Creates a message representing a given feed entry. """ logging.info("Creating message about: " + entry.title) msg = email.mime.multipart.MIMEMultipart('alternative') msg.set_charset(self.feed.encoding) author = self.title() try: author = entry.author + " @ " + author except AttributeError: pass msg['From'] = author msg['Subject'] = entry.title msg['To'] = config.username date = time.time() if hasattr(entry, 'updated_parsed') \ and entry.updated_parsed is not None: date = entry.updated_parsed elif hasattr(entry, 'published_parsed') \ and entry.published_parsed is not None: date = entry.published_parsed else: logging.warning('Entry without a date: ' + entry.title) if date is not None: msg['Date'] = email.utils.format_datetime( datetime.datetime.fromtimestamp( time.mktime(date))) headerName = 'X-Entry-Link' msg[headerName] = email.header.Header(s=entry.link, charset=self.feed.encoding) try: content = entry.content[0]['value'] except AttributeError: try: content = entry.summary except AttributeError: content = entry.description html = content text = html2text.html2text(html) text = 'Retrieved from ' + entry.link + '\n' + text html = html + \ '<p><a href="' + \ entry.link + \ '">Retrieved from ' + \ entry.link + \ '</a></p>' part1 = email.mime.text.MIMEText(text, 'plain') part2 = email.mime.text.MIMEText(html, 'html') msg.attach(part1) msg.attach(part2) bytesIO = BytesIO() bytesGenerator = BytesGenerator(bytesIO, mangle_from_=True, maxheaderlen=60) bytesGenerator.flatten(msg) text = bytesIO.getvalue() return text
def test_cte_type_7bit_handles_unknown_8bit(self): source = ("Subject: Maintenant je vous présente mon " "collègue\n\n").encode('utf-8') expected = ('Subject: Maintenant je vous =?unknown-8bit?q?' 'pr=C3=A9sente_mon_coll=C3=A8gue?=\n\n').encode('ascii') msg = message_from_bytes(source) s = io.BytesIO() g = BytesGenerator(s, policy=self.policy.clone(cte_type='7bit')) g.flatten(msg) self.assertEqual(s.getvalue(), expected)
def mail_to_bytes(mail): """Get bytes based on a mail. Based on email.Message.as_bytes, but we reimplement it here because python 3.3 lacks it. """ fp = BytesIO() g = BytesGenerator(fp, mangle_from_=False, policy=mail.policy) g.flatten(mail, unixfrom=False) return fp.getvalue()
def main(do_it=False): with open('results.pkl', 'rb') as f: results = pickle.load(f) if not do_it: print('This only send data if you give it --ok') print('Would send the following mails:') print('') n = len(results) i = 0 for result in results: gifter = result[0] gifted = result[1] #mail_body = mail_body_fmt.format(gifter=result[0], gifted=result[1]) #mail_from = f'{sender_email}' #mail_to = f'{gifter.email}' mail_from = f'{sender_name} <{sender_email}>' mail_to = f'{gifter.name} <{gifter.email}>' mail_subject = mail_subject_fmt.format() mail_body = mail_body_fmt.format(gifter=gifter, gifted=gifted) msg = EmailMessage() msg['From'] = mail_from msg['To'] = mail_to msg['Subject'] = mail_subject msg.set_payload(mail_body, charset='utf-8') if do_it: #p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE) #p.communicate(msg.as_bytes()) p = Popen(['sendmail', '-F', '-oi', gifter.email], stdin=PIPE) g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n')) g.flatten(msg) p.stdin.close() rc = p.wait() i += 1 print(f'{i}/{n} mails sent.') else: # because utf8 is 8b and transport is 7b, mail is normally encoded in base64 # this is just a way to add the un-encoded text to the message before printing # trying to send it will give errors msg.set_payload(mail_body) print('-' * 78) print(msg) print('-' * 78) if do_it and i != n: print('There were some errors sending the mails') os.remove('results.pkl')
def write_message_to_file(message, filename): """ Write a message to the file with the given filename. """ fp = open(os.path.join(args.dir, filename), "wb") try: generator = BytesGenerator(fp) generator.flatten(message, linesep="\r\n") finally: fp.close()
def as_bytes(self): """ converts the mail into a binary string @return bytes See `Message.as_bytes <https://docs.python.org/3/library/email.message.html#email.message.Message.as_bytes>`_ """ fp = BytesIO() g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60) g.flatten(self) return fp.getvalue()
def main(): last_month = datetime.date.today().replace(day=1) - datetime.timedelta(days=1) mails = get_mails() if not mails: print("No mails") return files = get_files(last_month) if not files: print("No files") return multipart = MIMEMultipart() multipart['Subject'] = last_month.strftime("Temp: %Y-%m") multipart['From'] = str(Address("Temperatura", addr_spec="*****@*****.**")) multipart['To'] = ', '.join(str(m) for m in mails) multipart.attach(MIMEText("""\ Witaj! W załączeniu zapisy temperatury z ostatniego miesiąca. --Temperatura""")) for filepath in files: if not filepath.is_file(): continue ctype, encoding = mimetypes.guess_type(filepath.name) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) with filepath.open('rb') as f: attachment = MIMEBase(maintype, subtype) attachment.set_payload(f.read()) encoders.encode_base64(attachment) attachment.add_header('Content-Disposition', 'attachment', filename=filepath.name) multipart.attach(attachment) with open(datetime.datetime.now().strftime('email-%Y-%m-%d-%H-%M-%s.msg'), 'wb') as f: fp = BytesIO() g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60) g.flatten(multipart) text = fp.getvalue() f.write(text) try: with smtplib.SMTP_SSL('poczta.o2.pl', port=465) as s: s.login('*****@*****.**', 'shtiSlaidd') s.send_message(multipart) except smtplib.SMTPResponseException as e: if e.smtp_code == 250 and e.smtp_error == b'Ok': pass # o2.pl bug. Returns 250 Ok instead of 221 else: raise
def select(self, mailbox='INBOX.' + config.mailbox): """ Selects given mailbox or mailbox given in config gile. """ logging.info("Selecting mailbox: " + mailbox) mbox = mailbox if mbox[0] != '"': mbox = '"' + mbox + '"' status, message = self.imap.select(mbox) if status == 'NO': # there's no such mailbox, let's create one self.imap.select() status, message = self.imap.create(mbox) if status != "OK": logging.error("Could not create mailbox: " + str(mbox)) self.imap.subscribe(mbox) status, message = self.imap.select(mbox) if status != "OK": logging.error("Could not select mailbox: " + str(mbox)) if mbox in ['"INBOX.testyarss2imap"', '"INBOX.' + config.mailbox + '"']: # The default yarss2imap mailbox was just created # Let's populate it with a README message. logging.info("Creating README message") msg = email.mime.multipart.MIMEMultipart('alternative') msg.set_charset("utf-8") msg['From'] = "*****@*****.**" msg['Subject'] = "Welcome to yarss2imap. README please." msg['To'] = config.username msg['Date'] = email.utils.format_datetime( datetime.datetime.fromtimestamp( time.time())) f = open('README.md','r') content = f.read() f.close() part = email.mime.text.MIMEText(content, 'plain') msg.attach(part) bytesIO = BytesIO() bytesGenerator = BytesGenerator(bytesIO, mangle_from_=True, maxheaderlen=60) bytesGenerator.flatten(msg) text = bytesIO.getvalue() status, error = self.imap.append( mbox, '', imaplib.Time2Internaldate(time.time()), text) if status != 'OK': logging.error('Could not append README message: ' + error) self.imap.select(mbox) return status
def as_bytes(self, unixfrom=False, policy=None): """Return the entire formatted message as a bytes object. Optional 'unixfrom', when true, means include the Unix From_ envelope header. 'policy' is passed to the BytesGenerator instance used to serialize the message; if not specified the policy associated with the message instance is used. """ from email.generator import BytesGenerator policy = self.policy if policy is None else policy fp = BytesIO() g = BytesGenerator(fp, mangle_from_=False, policy=policy) g.flatten(self, unixfrom=unixfrom) return fp.getvalue()
def as_bytes(self): """Return the entire formatted message as a bytes object.""" # Instead of using self.message.as_bytes() directly, # we copy and edit the implementation of email.Message.as_bytes # since it does not accept maxheaderlen, which we wish to set to 0 # for transparency. policy = self.message.policy fp = BytesIO() g = BytesGenerator(fp, mangle_from_=False, maxheaderlen=0, policy=policy) g.flatten(self.message, unixfrom=None) return fp.getvalue()
def test_smtputf8_policy(self): msg = EmailMessage() msg['From'] = 'Páolo <fő[email protected]>' msg['To'] = 'Dinsdale' msg['Subject'] = 'Nudge nudge, wink, wink ὠ9' msg.set_content('oh là là, know what I mean, know what I mean?') expected = textwrap.dedent(""" From: Páolo <fő[email protected]> To: Dinsdale Subject: Nudge nudge, wink, wink ὠ9 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit MIME-Version: 1.0 oh là là, know what I mean, know what I mean? """).encode('utf-8').replace(b'\n', b'\r\n') s = io.BytesIO() g = BytesGenerator(s, policy=policy.SMTPUTF8) g.flatten(msg) self.assertEqual(s.getvalue(), expected)
def test_smtputf8_policy(self): msg = EmailMessage() msg['From'] = "Páolo <fő[email protected]>" msg['To'] = 'Dinsdale' msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' msg.set_content("oh là là, know what I mean, know what I mean?") expected = textwrap.dedent("""\ From: Páolo <fő[email protected]> To: Dinsdale Subject: Nudge nudge, wink, wink \u1F609 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit MIME-Version: 1.0 oh là là, know what I mean, know what I mean? """).encode('utf-8').replace(b'\n', b'\r\n') s = io.BytesIO() g = BytesGenerator(s, policy=policy.SMTPUTF8) g.flatten(msg) self.assertEqual(s.getvalue(), expected)
def test_smtp_policy(self): msg = EmailMessage() msg["From"] = Address(addr_spec="*****@*****.**", display_name="Páolo") msg["To"] = Address(addr_spec="*****@*****.**", display_name="Dinsdale") msg["Subject"] = "Nudge nudge, wink, wink" msg.set_content("oh boy, know what I mean, know what I mean?") expected = textwrap.dedent("""\ From: =?utf-8?q?P=C3=A1olo?= <*****@*****.**> To: Dinsdale <*****@*****.**> Subject: Nudge nudge, wink, wink Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 oh boy, know what I mean, know what I mean? """).encode().replace(b"\n", b"\r\n") s = io.BytesIO() g = BytesGenerator(s, policy=policy.SMTP) g.flatten(msg) self.assertEqual(s.getvalue(), expected)
def ingest(self, file_path, entity): mbox = mailbox.mbox(file_path) entity.schema = model.get('Package') entity.add('mimeType', self.DEFAULT_MIME) for i, msg in enumerate(mbox.itervalues(), 1): # Is there a risk of https://bugs.python.org/issue27321 ? try: msg_path = self.make_work_file('%s.eml' % i) with open(msg_path, 'wb') as fh: gen = BytesGenerator(fh, policy=default) gen.flatten(msg) checksum = self.manager.store(msg_path, mime_type=RFC822) msg_path.unlink() child = self.manager.make_entity('Email', parent=entity) child.make_id(checksum) child.add('contentHash', checksum) child.add('mimeType', RFC822) self.manager.queue_entity(child) except Exception: log.exception("[%r] Cannot extract message %s", entity, i)
def encode_multipart_message(message): # The message must be multipart. assert message.is_multipart() # The body length cannot yet be known. assert "Content-Length" not in message # So line-endings can be fixed-up later on, component payloads must have # no Content-Length and their Content-Transfer-Encoding must be base64 # (and not quoted-printable, which Django doesn't appear to understand). for part in message.get_payload(): assert "Content-Length" not in part assert part["Content-Transfer-Encoding"] == "base64" # Flatten the message without headers. buf = BytesIO() generator = BytesGenerator(buf, False) # Don't mangle "^From". generator._write_headers = lambda self: None # Ignore. generator.flatten(message) # Ensure the body has CRLF-delimited lines. See # http://bugs.python.org/issue1349106. body = b"\r\n".join(buf.getvalue().splitlines()) # Only now is it safe to set the content length. message.add_header("Content-Length", "%d" % len(body)) return message.items(), body
text = lsb_release + '\n' + '\n'.join(env) attachment = MIMEText(text, _charset='UTF-8') attachment.add_header('Content-Disposition', 'inline') message = MIMEMultipart() message.add_header('Tags', 'snap') message.attach(attachment) blob = message.as_string().encode('UTF-8') url = 'https://{}/+storeblob'.format(LAUNCHPAD) data = MIMEMultipart() submit = MIMEText('1') submit.add_header('Content-Disposition', 'form-data; name="FORM_SUBMIT"') data.attach(submit) form_blob = MIMEBase('application', 'octet-stream') form_blob.add_header('Content-Disposition', 'form-data; name="field.blob"; filename="x"') form_blob.set_payload(blob.decode('ascii')) data.attach(form_blob) data_flat = BytesIO() gen = BytesGenerator(data_flat, mangle_from_=False) gen.flatten(data) request = Request(url, data_flat.getvalue()) request.add_header('Content-Type', 'multipart/form-data; boundary=' + data.get_boundary()) opener = build_opener(HTTPSHandler) result = opener.open(request) handle = result.info().get('X-Launchpad-Blob-Token') summary = '[snap] SUMMARY HERE'.encode('UTF-8') params = urlencode({'field.title': summary}) filebug_url = 'https://bugs.{}/ubuntu/+source/libreoffice/+filebug/{}?{}' subprocess.run(["xdg-open", filebug_url.format(LAUNCHPAD, handle, params)])
def msg_as_input(self, msg): m = message_from_bytes(msg, policy=policy.SMTP) b = io.BytesIO() g = BytesGenerator(b) g.flatten(m) self.assertEqual(b.getvalue(), msg)
def _flatten_message(self, message, flattening_policy): bytes_io = BytesIO() generator = BytesGenerator(bytes_io, mangle_from_=False, policy=flattening_policy) generator.flatten(message, unixfrom=False, linesep='\r\n') return bytes_io.getvalue()