def test_empty_message(self): msg = Message() msg["From"] = "*****@*****.**" msg["Subject"] = "subject (issue%s)\r\n\r\n" % self.issue.key().id() self.assertRaises( views.InvalidIncomingEmailError, views._process_incoming_mail, msg.as_string(), "*****@*****.**" )
def _send_message(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Message-ID"] = "<msg>" msg["Subject"] = "Dummy message" msg.set_payload("Dummy content") return add_to_list("*****@*****.**", msg)
def test_empty_message(self): msg = Message() msg['From'] = '*****@*****.**' msg['Subject'] = 'subject (issue%s)\r\n\r\n' % self.issue.key.id() self.assertRaises(views.InvalidIncomingEmailError, views._process_incoming_mail, msg.as_string(), '*****@*****.**')
def dump_message(file, headers, props=None, content=None): msg = Message() for (name, value) in headers: msg[name] = value payload = BytesIO() if props is not None: start = payload.tell() for (key, value) in props.items(): payload.write("K {}\n".format(len(key)).encode("ascii")) payload.writelines((key.encode("ascii"), b"\n")) payload.write("V {}\n".format(len(value)).encode("ascii")) payload.writelines((value.encode("ascii"), b"\n")) payload.write(b"PROPS-END\n") msg["Prop-content-length"] = format(payload.tell() - start) if content is not None: msg["Text-content-length"] = format(len(content)) payload.write(content) if props is not None or content is not None: payload = payload.getvalue() msg["Content-length"] = format(len(payload)) # Workaround for Python issue 18324, "set_payload does not handle # binary payloads correctly", http://bugs.python.org/issue18324 msg.set_payload(payload.decode("ascii", "surrogateescape")) BytesGenerator(file, mangle_from_=False).flatten(msg)
def _mail_missing_message(self, subject, text): # FIXME: This should be handled properly via the event api # we should send a missing message on the mq, and let any reporter # handle that # first, see if we have a MailNotifier we can use. This gives us a # fromaddr and a relayhost. buildmaster = self.botmaster.master for st in buildmaster.services: if isinstance(st, MailNotifier): break else: # if not, they get a default MailNotifier, which always uses SMTP # to localhost and uses a dummy fromaddr of "buildbot". log.msg("worker-missing msg using default MailNotifier") st = MailNotifier("buildbot") # now construct the mail m = Message() m.set_payload(text) m['Date'] = formatdate(localtime=True) m['Subject'] = subject m['From'] = st.fromaddr recipients = self.notify_on_missing m['To'] = ", ".join(recipients) d = st.sendMessage(m, recipients) # return the Deferred for testing purposes return d
def do_email(self): """将最终结果以邮件形式发送""" print "准备发送邮件..." from_addr = self.conf.get("addr", "from") to_addr = self.conf.get("addr", "to") cc_addr = self.conf.get("addr", "cc") smtpserver = self.conf.get("mail", "smtpserver") username = self.conf.get("mail", "username") password = self.conf.get("mail", "password") to_and_cc_addr = self._str2list(to_addr) + self._str2list(cc_addr) if self.do_check_email_conf(smtpserver, username, password, from_addr, to_and_cc_addr) is not True: return subject = self.program_range + self.program_type + time.strftime("(发送时间:%Y年%m月%d日)", time.localtime()) message = Message() message["Subject"] = subject message["From"] = from_addr message["To"] = to_addr message["Cc"] = cc_addr message.set_payload(self.file_content) smtp = smtplib.SMTP() smtp.connect(smtpserver) smtp.login(username, password) smtp.sendmail(from_addr, to_and_cc_addr, message.as_string()) smtp.quit() print "发送完毕,请到邮箱中查看抓取信息..."
def test_get_activities_extra_fetches_fail(self): """Sometimes the extras fetches return errors. Ignore that.""" self.init() batch = MIMEMultipart() for i in range(3): msg = Message() msg.set_payload('HTTP/1.1 500 Foo Bar\n\r\n\r\n') msg['Content-ID'] = '<response-abc+%d>' % (i + 1) batch.attach(msg) # as_string() must be called before get_boundary() to generate the # boundaries between parts, but can't be called again, so we capture the # result. batch_str = batch.as_string() self.auth_entity.http = lambda: http.HttpMockSequence( [({'status': '200'}, json.dumps({'items': [ACTIVITY_GP_EXTRAS]})), ({'status': '200', 'content-type': 'multipart/mixed; boundary="%s"' % batch.get_boundary()}, batch_str), ]) cache = util.CacheDict() self.assert_equals([ACTIVITY_AS], self.googleplus.get_activities( fetch_replies=True, fetch_likes=True, fetch_shares=True, cache=cache)) for prefix in 'AGC ', 'AGL ', 'AGS ': self.assertNotIn(prefix + '001', cache)
def test_payload_encoding_utf8(self): jhello = str(b'\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc' b'\xa5\xeb\xa5\xc9\xa1\xaa', 'euc-jp') msg = Message() msg.set_payload(jhello, 'utf-8') ustr = msg.get_payload(decode=True).decode(msg.get_content_charset()) self.assertEqual(jhello, ustr)
def test_matches(self): from email.message import Message msg = Message() msg.set_payload("I am full of happy babies. All days for Me!") fut = self._make_one() self.assertEqual(fut(msg), "body_regexp: body matches u'happy.+days'")
def test_as_message_attachments(self): msg_in = Message() msg_in["From"] = "*****@*****.**" msg_in["Message-ID"] = "<msg>" msg_in.attach(MIMEText("Dummy message")) msg_in.attach(MIMEText("<html><body>Dummy message</body></html>", _subtype="html")) add_to_list("*****@*****.**", msg_in) email = Email.objects.get(message_id="msg") msg = email.as_message() self.assertEqual(msg["From"], "dummy at example.com") self.assertEqual(msg["Message-ID"], "<msg>") self.assertTrue(msg.is_multipart()) payload = msg.get_payload() self.assertEqual(len(payload), 2) self.assertEqual( payload[0].get_payload(decode=True).strip(), "Dummy message") # The filename extension detection from content type is a bit random # (depends on the PYTHON_HASHSEED), make sure we get the right one # here for testing. expected_ext = guess_all_extensions("text/html", strict=False)[0] self.assertEqual(payload[1].get_content_type(), "text/html") self.assertEqual(payload[1]["Content-Disposition"], 'attachment; filename="attachment%s"' % expected_ext) self.assertEqual( payload[1].get_payload(decode=True), "<html><body>Dummy message</body></html>")
def message_to_string(self, recever_addr, title, text): message = Message() message['From'] = self.from_addr message['Subject'] = title message['To'] = recever_addr message.set_payload(text, charset='utf-8') return message.as_string()
def _cloneMessage(self, message): clone = Message() for key, value in message.items(): if key.lower() != 'message-id': clone[key] = value clone.set_payload(message.get_payload()) return clone
def test_payload_encoding(self): jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa' jcode = 'euc-jp' msg = Message() msg.set_payload(jhello, jcode) ustr = unicode(msg.get_payload(), msg.get_content_charset()) self.assertEqual(jhello, ustr.encode(jcode))
def send_mail(subject, content): smtpserver = 'smtp.gmail.com' username = '******' password = '******' from_addr = '*****@*****.**' to_addr = '*****@*****.**' mailtime = email.utils.formatdate(time.time(), True) message = Message() message['Subject'] = subject message['From'] = from_addr message['To'] = to_addr mailcontent = "\nQuery Time: {0}\n\n{1}\n\n".format(mailtime, content) message.set_payload(mailcontent) msg = message.as_string() sm = smtplib.SMTP(smtpserver, port=587, timeout=20) sm.set_debuglevel(1) sm.ehlo() sm.starttls() sm.ehlo() sm.login(username, password) sm.sendmail(from_addr, to_addr, msg) sleep(5) sm.quit()
def test_no_from(self): msg = Message() msg.set_payload("Dummy message") try: name, email = utils.parseaddr(msg["From"]) except AttributeError, e: self.fail(e)
def register_view(context, request): form = Form(Signup(), buttons=('register',)) rendered_form = form.render(null) if 'register' in request.POST: try: appstruct = form.validate(request.POST.items()) except ValidationFailure, e: rendered_form = e.render() else: pending = request.registry.queryAdapter(context, IRegistrations, name='pending') if pending is None: #pragma NO COVERAGE pending = PendingRegistrations(context) email = appstruct['email'] token = getRandomToken(request) pending.set(email, token=token) from_addr = request.registry.settings['cartouche.from_addr'] delivery = request.registry.queryUtility(IMailDelivery, default=localhost_mta) confirmation_url = view_url(context, request, 'confirmation_url', 'confirm_registration.html', email=email) body = REGISTRATION_EMAIL % {'token': token, 'confirmation_url': confirmation_url} message = Message() message['Subject'] = 'Site registration confirmation' message.set_payload(body) delivery.send(from_addr, [email], message) return HTTPFound(location=confirmation_url)
def _add_message(self, msgid="msg"): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Message-ID"] = "<%s>" % msgid msg["Subject"] = "Dummy message" msg.set_payload("Dummy content with keyword") return add_to_list("*****@*****.**", msg)
def setUp(self): # Create the list by adding a dummy message msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg)
def test_get_threads_between(self): # the get_threads_between method should return all threads that have # been active between the two specified dates, including the threads # started in between those dates but updated later msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-02-15 00:00:00 UTC" msg1.set_payload("message 1") add_to_list(self.ml.name, msg1) # The thread started in Feb, it should show up in the Feb threads but # not in the January or March threads. self.assertEqual(Thread.objects.count(), 1) jan_threads = self.ml.get_threads_between( datetime(2015, 1, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 1, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(jan_threads.count(), 0) feb_threads = self.ml.get_threads_between( datetime(2015, 2, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 2, 28, 0, 0, 0, tzinfo=utc), ) self.assertEqual(feb_threads.count(), 1) march_threads = self.ml.get_threads_between( datetime(2015, 3, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 3, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(march_threads.count(), 0)
def test_since_override(self): # When there's mail already and the "since" option is not used, it # defaults to the last email's date msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-01-01 12:00:00" msg1.set_payload("msg1") add_to_list("*****@*****.**", msg1) mailbox.mbox(os.path.join(self.tmpdir, "test.mbox")) # do the import output = StringIO() with patch("hyperkitty.management.commands.hyperkitty_import.DbImporter" ) as DbImporterMock: instance = Mock() instance.impacted_thread_ids = [] DbImporterMock.side_effect = lambda *a, **kw: instance self.command.execute(os.path.join(self.tmpdir, "test.mbox"), verbosity=2, stdout=output, stderr=output, list_address="*****@*****.**", since="2010-01-01 00:00:00 UTC", no_download=True, no_sync_mailman=True, ) self.assertEqual(DbImporterMock.call_args[0][1]["since"], datetime(2010, 1, 1, tzinfo=utc))
def test_delivery(self): from email.message import Message from_addr = "*****@*****.**" to_addr = "*****@*****.**" message = Message() message['Subject'] = 'Pants' message.set_payload('Nice pants, mister!') import transaction transaction.manager.begin() self.delivery.send(from_addr, to_addr, message) self.delivery.send(from_addr, to_addr, message) transaction.manager.commit() queued_messages = [m for m in self.maildir] self.assertEqual(2, len(queued_messages)) self.assertEqual(0, len(self.mailer.sent_messages)) cmdline = "qp %s" % self.queue_dir app = ConsoleApp(cmdline.split()) app.mailer = self.mailer app.main() queued_messages = [m for m in self.maildir] self.assertEqual(0, len(queued_messages)) self.assertEqual(2, len(self.mailer.sent_messages))
def test_wrong_encoding(self): """badly encoded message, only fails on PostgreSQL""" db_engine = settings.DATABASES[DEFAULT_DB_ALIAS]["ENGINE"] if db_engine == "django.db.backends.sqlite3": raise SkipTest # SQLite will accept anything with open(get_test_file("payload-utf8-wrong.txt")) as email_file: msg = message_from_file(email_file) mbox = mailbox.mbox(os.path.join(self.tmpdir, "test.mbox")) mbox.add(msg) # Second message msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg1>" msg["Date"] = "2015-02-01 12:00:00" msg.set_payload("msg1") mbox.add(msg) # do the import output = StringIO() kw = self.common_cmd_args.copy() kw["stdout"] = kw["stderr"] = output self.command.execute(os.path.join(self.tmpdir, "test.mbox"), **kw) # Message 1 must have been rejected, but no crash self.assertIn("Message wrong.encoding failed to import, skipping", output.getvalue()) # Message 2 must have been accepted self.assertEqual(MailingList.objects.count(), 1) self.assertEqual(Email.objects.count(), 1)
def test_delete_single_in_thread(self): # Delete an email in a thread that contains other emails self.user.is_staff = True self.user.save() msg = Email.objects.get(message_id="msg") msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = "<msg>" msg2.set_payload("Dummy message") add_to_list("*****@*****.**", msg2) msg2 = Email.objects.get(message_id="msg2") thread_id = msg.thread.thread_id url = reverse('hk_message_delete', args=("*****@*****.**", msg.message_id_hash)) response = self.client.post(url, {"email": msg.pk}) self.assertRedirects( response, reverse('hk_thread', kwargs={ "mlist_fqdn": "*****@*****.**", "threadid": thread_id})) # Flash message messages = get_flash_messages(response) self.assertEqual(len(messages), 1) self.assertEqual(messages[0].tags, "success") # The message must be deleted, but not the other message or the thread. self.assertFalse(Email.objects.filter(message_id="msg").exists()) self.assertTrue(Email.objects.filter(message_id="msg2").exists()) thread = Thread.objects.get(thread_id=thread_id) self.assertIsNotNone(thread) # msg2 must now be the thread starter. msg2.refresh_from_db() self.assertIsNone(msg2.parent_id) self.assertEqual(thread.starting_email.message_id, "msg2")
def handler(doc): # a 'rfc822' stores 'headers' as a dict, with each entry being a list. # We only care about headers which rfc5322 must appear 0 or 1 times, so # flatten the header values here... headers = dict((k, v[0]) for (k, v) in doc['headers'].iteritems()) # for now, 'from' etc are all tuples of [identity_type, identity_id] callbacks = [] ret = {} if 'from' in headers: name, addr = parseaddr(headers['from']) ret['from'] = ['email', addr.lower()] ret['from_display'] = name if 'to' in headers: id_list = ret['to'] = [] disp_list = ret['to_display'] = [] fill_identity_info(headers['to'], id_list, disp_list) if 'cc' in headers: id_list = ret['cc'] = [] disp_list = ret['cc_display'] = [] fill_identity_info(headers['cc'], id_list, disp_list) if 'subject' in headers: ret['subject'] = headers['subject'] if 'timestamp' in doc: ret['timestamp'] = doc['timestamp'] # body handling if doc.get('multipart'): infos = doc['multipart_info'] else: aname, attach = get_schema_attachment_info(doc, 'body') infos = [{'content_type': attach['content_type'], 'name': 'body'}] parts = [] docid = doc['_id'] for info in infos: # Use the email package to help parse the charset... m = Message() m['content-type'] = info['content_type'] charset = m.get_content_charset() ct = m.get_content_type() if ct == 'text/plain': name = info['name'] content = open_schema_attachment(doc, name) parts.append(decode_body_part(docid, content, charset)) # else: we should annotate the object with non-plaintext # attachment information XXX ret['body'] = '\n'.join(parts) ret['body_preview'] = extract_preview(ret['body']) try: # If the provider could supply tags then pass them on ret['tags'] = doc['tags'] except KeyError: pass emit_schema('rd.msg.body', ret)
def urlgetcontent(self, container, url, data = None, method = None, headers = {}, tostr = False, encoding = None, rawurl = False, *args, **kwargs): ''' In Python2, bytes = str, so tostr and encoding has no effect. In Python3, bytes are decoded into unicode str with encoding. If encoding is not specified, charset in content-type is used if present, or default to utf-8 if not. See open for available arguments :param rawurl: if True, assume the url is already url-encoded, do not encode it again. ''' req = Request(url, data, method, headers, rawurl = rawurl) for m in self.open(container, req, *args, **kwargs): yield m resp = container.retvalue encoding = 'utf-8' if encoding is None: m = Message() m.add_header('Content-Type', resp.get_header('Content-Type', 'text/html')) encoding = m.get_content_charset('utf-8') if not resp.stream: content = b'' else: for m in resp.stream.read(container): yield m content = container.data if tostr: content = _str(content, encoding) container.retvalue = content
def generate_msg(self, code, sendid): msg = Message() msg.set_payload(code) msg['Subject'] = 'Rummager (sendid: %s)' % (sendid,) msg['From'] = '*****@*****.**' msg['To'] = '*****@*****.**' return msg
def recover_account_view(context, request): form = Form(RecoverAccount(), buttons=('recover',)) rendered_form = form.render(null) confirmed = request.registry.queryAdapter(context, IRegistrations, name='confirmed') if confirmed is None: #pragma NO COVERAGE confirmed = ConfirmedRegistrations(context) login_url = view_url(context, request, 'login_url', 'login.html') registry = request.registry message = request.GET.get('message') if 'recover' in request.POST: try: appstruct = form.validate(request.POST.items()) except ValidationFailure, e: #pragma NO COVER rendered_form = e.render() else: email = appstruct['email'] record = confirmed.get_by_email(email) if record is not None: from_addr = registry.settings['cartouche.from_addr'] login = record.login body = RECOVERY_EMAIL % {'login': login, 'login_url': login_url} delivery = registry.queryUtility(IMailDelivery, default=localhost_mta) email_message = Message() email_message['Subject'] = 'Account recovery' email_message.set_payload(body) delivery.send(from_addr, [email], email_message) #else: # DO NOT report lookup errors return HTTPFound(location=login_url)
def test_delete_all_messages_in_thread(self): self.user.is_staff = True self.user.save() msg = Email.objects.get(message_id="msg") msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = "<msg>" msg2.set_payload("Dummy message") add_to_list("*****@*****.**", msg2) msg2 = Email.objects.get(message_id="msg2") thread_id = msg.thread.pk url = reverse('hk_thread_delete', args=("*****@*****.**", msg.thread.thread_id)) response = self.client.post(url, {"email": [msg.pk, msg2.pk]}) self.assertRedirects( response, reverse('hk_list_overview', kwargs={ "mlist_fqdn": "*****@*****.**"})) # Flash message messages = get_flash_messages(response) self.assertEqual(len(messages), 1) self.assertEqual(messages[0].tags, "success") # Alls messages and the thread must be deleted. self.assertFalse(Email.objects.filter(message_id="msg").exists()) self.assertFalse(Email.objects.filter(message_id="msg2").exists()) self.assertFalse(Thread.objects.filter(pk=thread_id).exists())
def post(self, folder, subject="", body="", date=None, headers={}, metadata={}): folder_name = self.select_or_create_folder(folder) # create the post as a new email m = Message() m["From"] = self.email # m["To"] = "*****@*****.**" m["Content-Type"] = "text/plain" if subject: m["Subject"] = subject # Javascript should use d.toString() = "Sun Jun 09 2013 16:21:47 GMT+0800 (WST)" msg_time = (date and dateutil.parser.parse(date) or None) if msg_time: # Date - # djb nails it: # http://cr.yp.to/immhf/date.html # Date: 23 Dec 1995 19:25:43 -0000 m["Date"] = msg_time.strftime("%a, %d %b %Y %X %z") # set any other headers for h in headers: m[h] = headers[h] for md in metadata: m[json_marker + md] = json.dumps(metadata[md]) # set the content of the message if body: m.set_payload(body) response = self.append(folder_name, m.as_string(), msg_time=msg_time) #print response # u'[APPENDUID 594556012 1] (Success)' # u'[APPENDUID 1370766584 11] Append completed.' result = {"message": None, "codes": []} if append_response_re.match(response): result = append_response_re.match(response).groupdict() result["codes"] = result["codes"].split(" ") result["UID"] = int(result["codes"][:].pop()) return result, m
def process(self, message: Message): """Displays desktop notification about specified message. :param message: E-Mail message object. """ print(" - {}: {}.process()".format(self.name, self.__class__.__name__)) notify2.init("Sendmail") title = self.title_template.format( subject=message.get("Subject"), from_email=message.get("From"), appname="Sendmail", name=self.name ) text = self.text_template.format( subject=message.get("Subject"), from_email=message.get("From"), text=message.as_string(), appname="Sendmail", name=self.name ) n = notify2.Notification(title, text, self.icon_name ) n.show()
def prepare_multipart_body(self): # type: () -> None """Will prepare the body of this request according to the multipart information. This call assumes the on_request policies have been applied already in their correct context (sync/async) Does nothing if "set_multipart_mixed" was never called. """ if not self.multipart_mixed_info: return requests = self.multipart_mixed_info[0] # type: List[HttpRequest] boundary = self.multipart_mixed_info[2] # type: Optional[str] # Update the main request with the body main_message = Message() main_message.add_header("Content-Type", "multipart/mixed") if boundary: main_message.set_boundary(boundary) for i, req in enumerate(requests): part_message = Message() part_message.add_header("Content-Type", "application/http") part_message.add_header("Content-Transfer-Encoding", "binary") part_message.add_header("Content-ID", str(i)) part_message.set_payload(req.serialize()) main_message.attach(part_message) try: from email.policy import HTTP full_message = main_message.as_bytes(policy=HTTP) eol = b"\r\n" except ImportError: # Python 2.7 # Right now we decide to not support Python 2.7 on serialization, since # it doesn't serialize a valid HTTP request (and our main scenario Storage refuses it) raise NotImplementedError( "Multipart request are not supported on Python 2.7" ) # full_message = main_message.as_string() # eol = b'\n' _, _, body = full_message.split(eol, 2) self.set_bytes_body(body) self.headers["Content-Type"] = ( "multipart/mixed; boundary=" + main_message.get_boundary() )
def __setitem__(self, name, value): rc = Message.__setitem__(self, name, value) self.modified = True if self.headerchange: self.headerchange(self, name, str(value)) return rc
def parse_pgpmime(self, message): sig_count, sig_parts, sig_alg = 0, [], 'SHA1' enc_count, enc_parts, enc_ver = 0, [], None for part in message.walk(): mimetype = part.get_content_type() if (sig_count > 1) and (mimetype == 'application/pgp-signature'): sig = part.get_payload() msg = '\r\n'.join( sig_parts[0].as_string().splitlines(False)) + '\r\n' result = None gpg = GnuPG() status = gpg.verify(msg, sig) print status for sig_part in sig_parts: print "sig_part: ", dir(sig_part), type(sig_part) sig_part.openpgp = ("signed", status) part.openpgp = ("signed", status) # Reset! sig_count, sig_parts = 0, [] elif sig_count > 0: sig_parts.append(part) sig_count += 1 elif enc_count > 0 and (mimetype == 'application/octet-stream'): # FIXME: Decrypt and parse! crypt = tempfile.NamedTemporaryFile() crypt.write(part.get_payload()) crypt.flush() msg = '\r\n'.join(part.as_string().splitlines(False)) + '\r\n' result = None gpg = GnuPG() res, result = gpg.decrypt(msg) if res == 0: summary = ('decrypted', result) else: summary = ('encrypted', result) s = StringIO.StringIO() s.write(result) m = Parser().parse(s) m = Message() m.set_payload(result) part.set_payload([m]) part.openpgp = summary for enc_part in enc_parts: enc_part.openpgp = summary # Reset! enc_count, enc_parts = 0, [] elif mimetype == 'multipart/signed': sig_alg = part.get_param('micalg', 'pgp-sha1').split('-')[-1].upper() sig_count = 1 elif mimetype == 'multipart/encrypted': enc_count = 1
def set_payload(self, payload, charset=None): payload = payload.encode('utf-8') Message.set_payload(self, payload, self.get_charset())
def send(self, job, message, config=None): """ Sends mail using configured mail settings. If `attachments` is true, a list compromised of the following dict is required via HTTP upload: - headers(list) - name(str) - value(str) - params(dict) - content (str) [ { "headers": [ { "name": "Content-Transfer-Encoding", "value": "base64" }, { "name": "Content-Type", "value": "application/octet-stream", "params": { "name": "test.txt" } } ], "content": "dGVzdAo=" } ] """ syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_MAIL) interval = message.get('interval') if interval is None: interval = timedelta() else: interval = timedelta(seconds=interval) sw_name = self.middleware.call_sync('system.info')['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') if not config: config = self.middleware.call_sync('mail.config') 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') def read_json(): f = os.fdopen(job.read_fd, 'rb') 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() if message.get('attachments') else None if attachments: msg = MIMEMultipart() msg.preamble = message['text'] 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') subject = message.get('subject') if subject: msg['Subject'] = subject msg['From'] = config['fromemail'] msg['To'] = ', '.join(to) msg['Date'] = formatdate() local_hostname = socket.gethostname() 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()): if key in msg: msg.replace_header(key, val) else: msg[key] = val try: 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() syslog.syslog("sending mail to " + ','.join(to) + msg.as_string()[0:140]) server.sendmail(config['fromemail'], to, msg.as_string()) server.quit() except ValueError as ve: # Don't spam syslog with these messages. They should only end up in the # test-email pane. raise CallError(str(ve)) except smtplib.SMTPAuthenticationError as e: raise CallError( f'Authentication error ({e.smtp_code}): {e.smtp_error}', errno.EAUTH) except Exception as e: 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 apply(self, ui): # get message to forward if not given in constructor if not self.message: self.message = ui.current_buffer.get_selected_message() mail = self.message.get_email() envelope = Envelope() if self.inline: # inline mode # set body text name, address = self.message.get_author() timestamp = self.message.get_date() qf = settings.get_hook('forward_prefix') if qf: quote = qf(name, address, timestamp, ui=ui, dbm=ui.dbman) else: quote = 'Forwarded message from %s (%s):\n' % (name or address, timestamp) mailcontent = quote quotehook = settings.get_hook('text_quote') if quotehook: mailcontent += quotehook(self.message.accumulate_body()) else: quote_prefix = settings.get('quote_prefix') for line in self.message.accumulate_body().splitlines(): mailcontent += quote_prefix + line + '\n' envelope.body = mailcontent for a in self.message.get_attachments(): envelope.attach(a) else: # attach original mode # attach original msg original_mail = Message() original_mail.set_type('message/rfc822') original_mail['Content-Disposition'] = 'attachment' original_mail.set_payload(email_as_string(mail)) envelope.attach(Attachment(original_mail)) # copy subject subject = decode_header(mail.get('Subject', '')) subject = 'Fwd: ' + subject forward_subject_hook = settings.get_hook('forward_subject') if forward_subject_hook: subject = forward_subject_hook(subject) else: fsp = settings.get('forward_subject_prefix') if not subject.startswith(('Fwd:', fsp)): subject = fsp + subject envelope.add('Subject', subject) # set From-header and sending account try: from_header, account = determine_sender(mail, 'reply') except AssertionError as e: ui.notify(e.message, priority='error') return envelope.add('From', from_header) # continue to compose ui.apply_command( ComposeCommand(envelope=envelope, spawn=self.force_spawn))
def recognise(): stream = request.stream #=== This is the part I took out ===# # access_token, part1, part2 = request.host.split('.', 1)[0].split('-', 3) # lang = f"{part1}-{part2.upper()}" # auth_req = requests.get(f"{AUTH_URL}/api/v1/me/token", headers={'Authorization': f"Bearer {access_token}"}) # if not auth_req.ok: # abort(401) #=== --------------------------- ===# chunks = iter(list(parse_chunks(stream))) content = next(chunks).decode('utf-8') body = { 'config': { 'encoding': 'SPEEX_WITH_HEADER_BYTE', 'language_code': 'en-US', # hardcoded 'sample_rate_hertz': 16000, 'max_alternatives': 1, 'enableAutomaticPunctuation': True, # 'metadata': { # 'interaction_type': 'DICTATION', # 'microphone_distance': 'NEARFIELD', # }, }, 'audio': { 'content': base64.b64encode(b''.join((struct.pack('B', len(x)) + x for x in chunks))).decode('utf-8'), }, } result = requests.post( f'https://speech.googleapis.com/v1/speech:recognize?key={API_KEY}', json=body) result.raise_for_status() words = [] if 'results' in result.json(): for result in result.json()['results']: words.extend( { 'word': x, 'confidence': str(result['alternatives'][0]['confidence']), } for x in result['alternatives'][0]['transcript'].split(' ')) # Now for some reason we also need to give back a mime/multipart message... parts = MIMEMultipart() response_part = Message() response_part.add_header('Content-Type', 'application/JSON; charset=utf-8') if len(words) > 0: response_part.add_header('Content-Disposition', 'form-data; name="QueryResult"') words[0]['word'] += '\\*no-space-before' words[0]['word'] = words[0]['word'][0].upper() + words[0]['word'][1:] response_part.set_payload(json.dumps({ 'words': [words], })) else: response_part.add_header('Content-Disposition', 'form-data; name="QueryRetry"') # Other errors probably exist, but I don't know what they are. # This is a Nuance error verbatim. response_part.set_payload( json.dumps({ "Cause": 1, "Name": "AUDIO_INFO", "Prompt": "Sorry, speech not recognized. Please try again." })) parts.attach(response_part) parts.set_boundary('--Nuance_NMSP_vutc5w1XobDdefsYG3wq') response = Response( '\r\n' + parts.as_string().split("\n", 3)[3].replace('\n', '\r\n')) response.headers[ 'Content-Type'] = f'multipart/form-data; boundary={parts.get_boundary()}' return response
def _get_dehydrated_message(self, msg, record): settings = utils.get_settings() new = EmailMessage() if msg.is_multipart(): for header, value in msg.items(): new[header] = value for part in msg.get_payload(): new.attach(self._get_dehydrated_message(part, record)) elif (settings['strip_unallowed_mimetypes'] and not msg.get_content_type() in settings['allowed_mimetypes']): for header, value in msg.items(): new[header] = value # Delete header, otherwise when attempting to deserialize the # payload, it will be expecting a body for this. del new['Content-Transfer-Encoding'] new[settings['altered_message_header']] = ( 'Stripped; Content type %s not allowed' % (msg.get_content_type())) new.set_payload('') elif ((msg.get_content_type() not in settings['text_stored_mimetypes']) or ('attachment' in msg.get('Content-Disposition', ''))): filename = None raw_filename = msg.get_filename() if raw_filename: filename = utils.convert_header_to_unicode(raw_filename) if not filename: extension = mimetypes.guess_extension(msg.get_content_type()) else: _, extension = os.path.splitext(filename) if not extension: extension = '.bin' attachment = MessageAttachment() attachment.document.save( uuid.uuid4().hex + extension, ContentFile(BytesIO(msg.get_payload(decode=True)).getvalue())) attachment.message = record for key, value in msg.items(): attachment[key] = value attachment.save() placeholder = EmailMessage() placeholder[settings['attachment_interpolation_header']] = str( attachment.pk) new = placeholder else: content_charset = msg.get_content_charset() if not content_charset: content_charset = 'ascii' try: # Make sure that the payload can be properly decoded in the # defined charset, if it can't, let's mash some things # inside the payload :-\ msg.get_payload(decode=True).decode(content_charset) except LookupError: logger.warning("Unknown encoding %s; interpreting as ASCII!", content_charset) msg.set_payload( msg.get_payload(decode=True).decode('ascii', 'ignore')) except ValueError: logger.warning( "Decoding error encountered; interpreting %s as ASCII!", content_charset) msg.set_payload( msg.get_payload(decode=True).decode('ascii', 'ignore')) new = msg return new
def cb_action_REJECT(module, filepath): log.info(_("Rejecting message in %s (by module %s)") % (filepath, module)) # parse message headers message = Parser().parse(open(filepath, 'r'), True) envelope_sender = getaddresses(message.get_all('From', [])) recipients = getaddresses(message.get_all('To', [])) + \ getaddresses(message.get_all('Cc', [])) + \ getaddresses(message.get_all('X-Kolab-To', [])) _recipients = [] for recipient in recipients: if not recipient[0] == '': _recipients.append('%s <%s>' % (recipient[0], recipient[1])) else: _recipients.append('%s' % (recipient[1])) # TODO: Find the preferredLanguage for the envelope_sender user. ndr_message_subject = "Undelivered Mail Returned to Sender" ndr_message_text = _("""This is the email system Wallace at %s. I'm sorry to inform you we could not deliver the attached message to the following recipients: - %s Your message is being delivered to any other recipients you may have sent your message to. There is no need to resend the message to those recipients. """) % (constants.fqdn, "\n- ".join(_recipients)) diagnostics = _("""X-Wallace-Module: %s X-Wallace-Result: REJECT """) % (module) msg = MIMEMultipart("report") msg['From'] = "MAILER-DAEMON@%s" % (constants.fqdn) msg['To'] = formataddr(envelope_sender[0]) msg['Date'] = formatdate(localtime=True) msg['Subject'] = ndr_message_subject msg.preamble = "This is a MIME-encapsulated message." part = MIMEText(ndr_message_text) part.add_header("Content-Description", "Notification") msg.attach(part) _diag_message = Message() _diag_message.set_payload(diagnostics) part = MIMEMessage(_diag_message, "delivery-status") part.add_header("Content-Description", "Delivery Report") msg.attach(part) # @TODO: here I'm not sure message will contain the whole body # when we used headersonly argument of Parser().parse() above # delete X-Kolab-* headers del message['X-Kolab-From'] del message['X-Kolab-To'] part = MIMEMessage(message) part.add_header("Content-Description", "Undelivered Message") msg.attach(part) result = _sendmail("MAILER-DAEMON@%s" % (constants.fqdn), [formataddr(envelope_sender[0])], msg.as_string()) if result: os.unlink(filepath)
def _rehydrate(self, msg): new = EmailMessage() settings = utils.get_settings() if msg.is_multipart(): for header, value in msg.items(): new[header] = value for part in msg.get_payload(): new.attach(self._rehydrate(part)) elif settings['attachment_interpolation_header'] in msg.keys(): try: attachment = MessageAttachment.objects.get( pk=msg[settings['attachment_interpolation_header']]) for header, value in attachment.items(): new[header] = value encoding = new['Content-Transfer-Encoding'] if encoding and encoding.lower() == 'quoted-printable': # Cannot use `email.encoders.encode_quopri due to # bug 14360: http://bugs.python.org/issue14360 output = BytesIO() encode_quopri( BytesIO(attachment.document.read()), output, quotetabs=True, header=False, ) new.set_payload(output.getvalue().decode().replace( ' ', '=20')) del new['Content-Transfer-Encoding'] new['Content-Transfer-Encoding'] = 'quoted-printable' else: new.set_payload(attachment.document.read()) del new['Content-Transfer-Encoding'] encode_base64(new) except MessageAttachment.DoesNotExist: new[settings['altered_message_header']] = ( 'Missing; Attachment %s not found' % (msg[settings['attachment_interpolation_header']])) new.set_payload('') else: for header, value in msg.items(): new[header] = value new.set_payload(msg.get_payload()) return new
def add_payload(message, obj): payload = Message() encoding = obj.get("encoding", "utf-8") if encoding and (encoding.upper() in ("BASE64", "7BIT", "8BIT", "BINARY")): payload.add_header("Content-Transfer-Encoding", encoding) else: payload.set_charset(encoding) mime = obj.get("mime", None) if mime: payload.set_type(mime) if "text" in obj: payload.set_payload(obj["text"]) elif "payload" in obj: payload.set_payload(obj["payload"]) if "filename" in obj and obj["filename"]: payload.add_header("Content-Disposition", "attachment", filename=obj["filename"]) message.attach(payload)
def createEmail(self, msgdict, builderName, title, results, builds=None, patches=None, logs=None): text = msgdict['body'].encode(ENCODING) type = msgdict['type'] if 'subject' in msgdict: subject = msgdict['subject'].encode(ENCODING) else: subject = self.subject % { 'result': Results[results], 'projectName': title, 'title': title, 'builder': builderName } assert '\n' not in subject, \ "Subject cannot contain newlines" assert type in ('plain', 'html'), \ "'%s' message type must be 'plain' or 'html'." % type if patches or logs: m = MIMEMultipart() txt = MIMEText(text, type, ENCODING) m.attach(txt) else: m = Message() m.set_payload(text, ENCODING) m.set_type("text/%s" % type) m['Date'] = formatdate(localtime=True) m['Subject'] = subject m['From'] = self.fromaddr # m['To'] is added later if patches: for (i, patch) in enumerate(patches): a = self.patch_to_attachment(patch, i) m.attach(a) if logs: for log in logs: name = "%s.%s" % (log['stepname'], log['name']) if (self._shouldAttachLog(log['name']) or self._shouldAttachLog(name)): # Use distinct filenames for the e-mail summary if self.buildSetSummary: filename = "%s.%s" % (log['buildername'], name) else: filename = name text = log['content']['content'] a = MIMEText(text.encode(ENCODING), _charset=ENCODING) a.add_header('Content-Disposition', "attachment", filename=filename) m.attach(a) # @todo: is there a better way to do this? # Add any extra headers that were requested, doing WithProperties # interpolation if only one build was given if self.extraHeaders: extraHeaders = self.extraHeaders if len(builds) == 1: props = Properties.fromDict(builds[0]['properties']) extraHeaders = yield props.render(extraHeaders) for k, v in iteritems(extraHeaders): if k in m: twlog.msg("Warning: Got header " + k + " in self.extraHeaders " "but it already exists in the Message - " "not adding it.") m[k] = v defer.returnValue(m)
def new_message(self): from email.message import Message return Message()
import mimetypes import email.utils from email.message import Message import sys, smtplib import getpass, poplib #the first part of the program generates some default mail for the mail folder in root. file1.open('message1.txt', 'w') text = """Hello, This is a test message from Chapter 12. I hope you enjoy it! -- Anonymous""" msg = Message() msg['To'] = '*****@*****.**' msg['From'] = 'Test Sender <*****@*****.**>' msg['Subject'] = 'Test Message, Chapter 12' msg.set_payload(text) #attachment setup def attachment(filename): fd = open(filename, 'rb') mimetype, mimeencoding = mimetypes.guess_type(filename) if mimeencoding or (mimetype is None): mimetype = 'application/octet-stream' maintype, subtype = mimetype.split('/') if maintype == 'text':
def setUp(self): super(Direct_BasicPlain, self).setUp() self.msg = Message()
def insert(self, table, fields): def add_payload(message, obj): payload = Message() encoding = obj.get("encoding", "utf-8") if encoding and (encoding.upper() in ("BASE64", "7BIT", "8BIT", "BINARY")): payload.add_header("Content-Transfer-Encoding", encoding) else: payload.set_charset(encoding) mime = obj.get("mime", None) if mime: payload.set_type(mime) if "text" in obj: payload.set_payload(obj["text"]) elif "payload" in obj: payload.set_payload(obj["payload"]) if "filename" in obj and obj["filename"]: payload.add_header("Content-Disposition", "attachment", filename=obj["filename"]) message.attach(payload) mailbox = table.mailbox d = dict(((k.name, v) for k, v in fields)) date_time = d.get("created") or datetime.datetime.now() struct_time = date_time.timetuple() if len(d) > 0: message = d.get("email", None) attachments = d.get("attachments", []) content = d.get("content", []) flags = " ".join(["\\%s" % flag.capitalize() for flag in ("answered", "deleted", "draft", "flagged", "recent", "seen") if d.get(flag, False)]) if not message: from email.message import Message mime = d.get("mime", None) charset = d.get("encoding", None) message = Message() message["from"] = d.get("sender", "") message["subject"] = d.get("subject", "") message["date"] = self.convert_date(date_time, imf=True) if mime: message.set_type(mime) if charset: message.set_charset(charset) for item in ("to", "cc", "bcc"): value = d.get(item, "") if isinstance(value, basestring): message[item] = value else: message[item] = ";".join([i for i in value]) if (not message.is_multipart() and (not message.get_content_type().startswith( "multipart"))): if isinstance(content, basestring): message.set_payload(content) elif len(content) > 0: message.set_payload(content[0]["text"]) else: [add_payload(message, c) for c in content] [add_payload(message, a) for a in attachments] message = message.as_string() result, data = self.connection.append(mailbox, flags, struct_time, message) if result == "OK": uid = int(re.findall("\d+", str(data))[-1]) return self.db(table.uid==uid).select(table.id).first().id else: raise Exception("IMAP message append failed: %s" % data) else: raise NotImplementedError("IMAP empty insert is not implemented")
def test_sendToInterestedUsers_two_builds(self): from email.message import Message m = Message() mn = MailNotifier(fromaddr="*****@*****.**", lookup=None) mn.sendMessage = Mock() def fakeGetBuilder(buildername): if buildername == builder.name: return builder return None def fakeGetBuildRequests(self, bsid): return defer.succeed([{"buildername": "Builder", "brid": 1}]) builder = Mock() builder.name = "Builder" build1 = FakeBuildStatus(name="build") build1.result = FAILURE build1.finished = True build1.reason = "testReason" build1.builder = builder build2 = FakeBuildStatus(name="build") build2.result = FAILURE build2.finished = True build2.reason = "testReason" build2.builder = builder def fakeCreateEmail(msgdict, builderName, title, results, builds=None, patches=None, logs=None): # only concerned with m['To'] and m['CC'], which are added in # _got_recipients later return defer.succeed(m) mn.createEmail = fakeCreateEmail self.db = fakedb.FakeDBConnector(self) self.db.insertTestData([ fakedb.SourceStampSet(id=1099), fakedb.Buildset(id=99, sourcestampsetid=1099, results=SUCCESS, reason="testReason"), fakedb.BuildRequest(id=11, buildsetid=99, buildername='Builder'), fakedb.Build(number=0, brid=11), fakedb.Build(number=1, brid=11), fakedb.Change(changeid=9123), fakedb.Change(changeid=9124), fakedb.ChangeUser(changeid=9123, uid=1), fakedb.ChangeUser(changeid=9124, uid=2), fakedb.User(uid=1, identifier="tdurden"), fakedb.User(uid=2, identifier="user2"), fakedb.UserInfo(uid=1, attr_type='email', attr_data="*****@*****.**"), fakedb.UserInfo(uid=2, attr_type='email', attr_data="*****@*****.**") ]) def _getInterestedUsers(): # 'narrator' in this case is the owner, which tests the lookup return ["narrator"] build1.getInterestedUsers = _getInterestedUsers build2.getInterestedUsers = _getInterestedUsers def _getResponsibleUsers(): return ["Big Bob <*****@*****.**>"] build1.getResponsibleUsers = _getResponsibleUsers build2.getResponsibleUsers = _getResponsibleUsers # fake sourcestamp with relevant user bits ss1 = Mock(name="sourcestamp") fake_change1 = Mock(name="change") fake_change1.number = 9123 ss1.changes = [fake_change1] ss1.patch, ss1.addPatch = None, None ss2 = Mock(name="sourcestamp") fake_change2 = Mock(name="change") fake_change2.number = 9124 ss2.changes = [fake_change2] ss2.patch, ss1.addPatch = None, None def fakeGetSSlist(ss): return lambda: [ss] build1.getSourceStamps = fakeGetSSlist(ss1) build2.getSourceStamps = fakeGetSSlist(ss2) mn.master = self # FIXME: Should be FakeMaster self.status = mn.master_status = mn.buildMessageDict = Mock() mn.master_status.getBuilder = fakeGetBuilder mn.buildMessageDict.return_value = {"body": "body", "type": "text"} mn.buildMessage(builder.name, [build1, build2], build1.result) self.assertEqual(m['To'], "[email protected], [email protected]")
def send_raw(self, job, message, config=None): interval = message.get('interval') if interval is None: interval = timedelta() else: interval = timedelta(seconds=interval) sw_name = self.middleware.call_sync('system.info')['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') if not config: config = self.middleware.call_sync('mail.config') 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 = message['text'] 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'] = config['fromemail'] msg['To'] = ', '.join(to) if message.get('cc'): msg['Cc'] = ', '.join(message.get('cc')) msg['Date'] = formatdate() local_hostname = socket.gethostname() 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()): if key in msg: msg.replace_header(key, val) else: msg[key] = val syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_MAIL) try: 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(config['fromemail'], 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) 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 send_vacation(self, email, destination): """ Sends a vacation message to the destination address unless they have already been notified. :param user: The email of the user to send the message for :type user: str :param destination: The email address of the remote address :type destination: str """ log.debug('Attempting to send vacation message to %s from %s', destination, email) with self.db_session() as session: user = session.query(User).filter_by(email=email).first() if not user: raise UserNotFoundError(email) if not user.vacation: log.debug('User has no vacation message') return False if not user.vacation.active: log.debug('Vacation message is not active') return False try: recipient = Address.parse(destination) except Exception: return False # TODO: Add support for html vacation messages # Build up the response message here message = MIMEMessage() message.add_header('From', '%s <%s>' % (user.name, user.email)) message.add_header('To', str(recipient)) message.add_header('Date', formatdate()) message.add_header('Subject', user.vacation.subject) message.set_payload(user.vacation.body.encode('utf8')) # Send the message to the local SMTP server smtp = smtplib.SMTP('localhost') try: log.debug("Sending vacation notification to '%s' for '%s'", recipient.address, user.email) smtp.sendmail(user.email, recipient.address, str(message)) except smtplib.SMTPRecipientsRefused: log.debug( "Failed sending vacation notification to '%s' for '%s'", recipient.address, user.email) finally: smtp.close() # Store that the recipient has been notified so we don't spam them # with useless information. notification = VacationNotification() notification.on_vacation = user.email notification.notified = destination notification.notified_at = datetime.datetime.now() session.add(notification) # FIXME: This is a kludgy fix to prevent unrequired error messages # when a vacation message is attempted to be sent to the same person # more than once. This should be resolved properly by allowing # configurable notification intervals and modifying the database # accordingly. try: session.commit() except IntegrityError: session.rollback() return True
env = load_environment() # Process command line args. subject = sys.argv[1] # Administrator's email address. admin_addr = "administrator@" + env['PRIMARY_HOSTNAME'] # Read in STDIN. content = sys.stdin.read().strip() # If there's nothing coming in, just exit. if content == "": sys.exit(0) # create MIME message msg = Message() msg['From'] = "\"%s\" <%s>" % (env['PRIMARY_HOSTNAME'], admin_addr) msg['To'] = admin_addr msg['Subject'] = "[%s] %s" % (env['PRIMARY_HOSTNAME'], subject) msg.set_payload(content, "UTF-8") # send smtpclient = smtplib.SMTP('127.0.0.1', 25) smtpclient.ehlo() smtpclient.sendmail( admin_addr, # MAIL FROM admin_addr, # RCPT TO msg.as_string()) smtpclient.quit()
def prepare_multipart_body(self, content_index=0): # type: (int) -> int """Will prepare the body of this request according to the multipart information. This call assumes the on_request policies have been applied already in their correct context (sync/async) Does nothing if "set_multipart_mixed" was never called. :param int content_index: The current index of parts within the batch message. :returns: The updated index after all parts in this request have been added. :rtype: int """ if not self.multipart_mixed_info: return 0 requests = self.multipart_mixed_info[0] # type: List[HttpRequest] boundary = self.multipart_mixed_info[2] # type: Optional[str] # Update the main request with the body main_message = Message() main_message.add_header("Content-Type", "multipart/mixed") if boundary: main_message.set_boundary(boundary) for req in requests: part_message = Message() if req.multipart_mixed_info: content_index = req.prepare_multipart_body( content_index=content_index) part_message.add_header("Content-Type", req.headers['Content-Type']) payload = req.serialize() # We need to remove the ~HTTP/1.1 prefix along with the added content-length payload = payload[payload.index(b'--'):] else: part_message.add_header("Content-Type", "application/http") part_message.add_header("Content-Transfer-Encoding", "binary") part_message.add_header("Content-ID", str(content_index)) payload = req.serialize() content_index += 1 part_message.set_payload(payload) main_message.attach(part_message) try: from email.policy import HTTP full_message = main_message.as_bytes(policy=HTTP) eol = b"\r\n" except ImportError: # Python 2.7 # Right now we decide to not support Python 2.7 on serialization, since # it doesn't serialize a valid HTTP request (and our main scenario Storage refuses it) raise NotImplementedError( "Multipart request are not supported on Python 2.7") # full_message = main_message.as_string() # eol = b'\n' _, _, body = full_message.split(eol, 2) self.set_bytes_body(body) self.headers["Content-Type"] = ("multipart/mixed; boundary=" + main_message.get_boundary()) return content_index
def do_test_sendToInterestedUsers(self, lookup=None, extraRecipients=[], sendToInterestedUsers=True, exp_called_with=None, exp_TO=None, exp_CC=None): from email.message import Message m = Message() mn = MailNotifier(fromaddr='*****@*****.**', lookup=lookup, sendToInterestedUsers=sendToInterestedUsers, extraRecipients=extraRecipients) mn.sendMessage = Mock() def fakeGetBuild(number): return build def fakeGetBuilder(buildername): if buildername == builder.name: return builder return None def fakeGetBuildRequests(self, bsid): return defer.succeed([{"buildername": "Builder", "brid": 1}]) builder = Mock() builder.getBuild = fakeGetBuild builder.name = "Builder" build = FakeBuildStatus(name="build") build.result = FAILURE build.finished = True build.reason = "testReason" build.builder = builder def fakeCreateEmail(msgdict, builderName, title, results, builds=None, patches=None, logs=None): # only concerned with m['To'] and m['CC'], which are added in # _got_recipients later return defer.succeed(m) mn.createEmail = fakeCreateEmail self.db = fakedb.FakeDBConnector(self) self.db.insertTestData([ fakedb.SourceStampSet(id=1099), fakedb.Buildset(id=99, sourcestampsetid=1099, results=SUCCESS, reason="testReason"), fakedb.BuildRequest(id=11, buildsetid=99, buildername='Builder'), fakedb.Build(number=0, brid=11), fakedb.Change(changeid=9123), fakedb.ChangeUser(changeid=9123, uid=1), fakedb.User(uid=1, identifier="tdurden"), fakedb.UserInfo(uid=1, attr_type='svn', attr_data="tdurden"), fakedb.UserInfo(uid=1, attr_type='email', attr_data="*****@*****.**") ]) # fake sourcestamp with relevant user bits ss = Mock(name="sourcestamp") fake_change = Mock(name="change") fake_change.number = 9123 ss.changes = [fake_change] ss.patch, ss.addPatch = None, None def fakeGetSSlist(): return [ss] build.getSourceStamps = fakeGetSSlist def _getInterestedUsers(): # 'narrator' in this case is the owner, which tests the lookup return ["narrator"] build.getInterestedUsers = _getInterestedUsers def _getResponsibleUsers(): return ["Big Bob <*****@*****.**>"] build.getResponsibleUsers = _getResponsibleUsers mn.master = self # FIXME: Should be FakeMaster self.status = mn.master_status = mn.buildMessageDict = Mock() mn.master_status.getBuilder = fakeGetBuilder mn.buildMessageDict.return_value = {"body": "body", "type": "text"} mn.buildMessage(builder.name, [build], build.result) mn.sendMessage.assert_called_with(m, exp_called_with) self.assertEqual(m['To'], exp_TO) self.assertEqual(m['CC'], exp_CC)
def createEmail(self, msgdict, builderName, title, results, builds=None, patches=None, logs=None): text = msgdict['body'].encode(ENCODING) type = msgdict['type'] if 'subject' in msgdict: subject = msgdict['subject'].encode(ENCODING) else: subject = self.subject % { 'result': Results[results], 'projectName': title, 'title': title, 'builder': builderName, } assert '\n' not in subject, \ "Subject cannot contain newlines" assert type in ('plain', 'html'), \ "'%s' message type must be 'plain' or 'html'." % type if patches or logs: m = MIMEMultipart() m.attach(MIMEText(text, type, ENCODING)) else: m = Message() m.set_payload(text, ENCODING) m.set_type("text/%s" % type) m['Date'] = formatdate(localtime=True) m['Subject'] = subject m['From'] = self.fromaddr # m['To'] is added later if patches: for (i, patch) in enumerate(patches): a = self.patch_to_attachment(patch, i) m.attach(a) if logs: for log in logs: name = "%s.%s" % (log.getStep().getName(), log.getName()) if (self._shouldAttachLog(log.getName()) or self._shouldAttachLog(name)): # Use distinct filenames for the e-mail summary if self.buildSetSummary: filename = "%s.%s.%s" % ( log.getStep().getBuild().getBuilder().getName(), log.getStep().getName(), log.getName()) else: filename = name text = log.getText() if not isinstance(text, unicode): # guess at the encoding, and use replacement symbols # for anything that's not in that encoding text = text.decode(LOG_ENCODING, 'replace') a = MIMEText(text.encode(ENCODING), _charset=ENCODING) a.add_header('Content-Disposition', "attachment", filename=filename) m.attach(a) #@todo: is there a better way to do this? # Add any extra headers that were requested, doing WithProperties # interpolation if only one build was given if self.extraHeaders: if len(builds) == 1: d = builds[0].render(self.extraHeaders) else: d = defer.succeed(self.extraHeaders) @d.addCallback def addExtraHeaders(extraHeaders): for k, v in extraHeaders.items(): if k in m: twlog.msg("Warning: Got header " + k + " in self.extraHeaders " "but it already exists in the Message - " "not adding it.") m[k] = v d.addCallback(lambda _: m) return d return defer.succeed(m)
def limit_reached_alert(user, limit_type, limit, value): """ Send out a notification when a limit is reached. :param user: The user who has hit the limit :type user: User :param limit_type: The type of limit that has been reached :type limit_type: str :param limit: The limit amount :type limit: int :param value: The number of messages sent :type value: int """ name = get_config('alerts_name') faddr = get_config('alerts_from') taddr = get_config('alerts_to') message = MIMEMessage() message.add_header('From', '"%s" <%s>' % (name, faddr)) if isinstance(taddr, list): message.add_header('To', ', '.join(taddr)) else: message.add_header('To', taddr) message.add_header('Date', formatdate()) message.add_header('Subject', 'User %s reached sending limit' % user.email) message.set_payload("""Hi, The user has reached their %s limit of sending messages. They have sent %d messages and have a limit of %d""" % (limit_type, value, limit)) # Send the message to the local SMTP server smtp = smtplib.SMTP('localhost') smtp.sendmail(faddr, taddr, str(message)) smtp.close()
#!/usr/bin/env python3 # Foundations of Python Network Programming, Third Edition # https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter12/pre-python-3.4/trad_gen_newhdrs.py # Traditional Message Generation with Date and Message-ID import email.utils from email.message import Message message = """Hello, This is a test message from Chapter 12. I hope you enjoy it! -- Anonymous""" msg = Message() msg['To'] = '*****@*****.**' msg['From'] = 'Test Sender <*****@*****.**>' msg['Subject'] = 'Test Message, Chapter 12' msg['Date'] = email.utils.formatdate(localtime=1) msg['Message-ID'] = email.utils.make_msgid() msg.set_payload(message) print(msg.as_string())
def sendMessage(self, From, To, Subj, extrahdrs, bodytext, attaches, saveMailSeparator=(('=' * 80) + 'PY\n'), bodytextEncoding='us-ascii', attachesEncodings=None): """ formats and sends an e-mail. saves the sent e-mail if sent sucessfully. arguments: bodytext - text part of the e-mail (assumes it is already in desired encoding.) attaches - list of files to be attached extrahdrs - list of tuples to be added (Name, Value) """ # body text encoding if fix_text_required(bodytextEncoding): if not isinstance(bodytext, str): bodytext = bodytext.decode(bodytextEncoding) else: if not isinstance(bodytext, bytes): bodytext = bodytext.encode(bodytextEncoding) # attachments if not attaches: msg = Message() msg.set_payload(bodytext, charset=bodytextEncoding) else: msg = MIMEMultipart() self.addAttachments(msg, bodytext, attaches, bodytextEncoding, attachesEncodings) # e-mail header encoding hdrenc = mailconfig.headersEncodeTo or 'utf-8' Subj = self.encodeHeader(Subj, hdrenc) From = self.encodeAddrHeader(From, hdrenc) To = [self.encodeAddrHeader(T, hdrenc) for T in To] Tos = ', '.join(To) # attach header to message msg['From'] = From msg['To'] = Tos msg['Subj'] = Subj msg['Date'] = email.utils.formatdate() recip = To for (name, value) in extrahdrs: if value: if name.lower() not in ['cc', 'bcc']: value = self.encodeHeader(value, hdrenc) msg[name] = value else: value = [self.encodeAddrHeader(V, hdrenc) for V in value] recip += value if name.lower() != 'bcc': msg[name] = ', '.join(value) # remove duplicates recip = list(set(recip)) fullText = msg.as_string() self.trace('Sending to...' + str(recip)) self.trace(fullText[:self.tracesize]) # smtp connection. server = smtplib.SMTP_SSL(self.smtpservername) self.getPassword() self.authenticateServer(server) try: failed = server.sendmail(From, recip, fullText) except Exception: server.close() raise else: server.quit() self.saveSentMessage(fullText, saveMailSeparator) if failed: class SomeAddrsFailed(Exception): pass raise SomeAddrsFailed('Failed addrs:%s\n' % failed) self.trace('Send exit')
def message_is_binary(message: Message) -> bool: """ Determine if a non-multipart message is of binary type. """ return message.get_content_maintype() not in ('text', 'message')
def copy(msg: Message) -> Message: """return a copy of message""" return email.message_from_bytes(msg.as_bytes())
def test_get_activities_fetch_extras(self): self.init() # Generate minimal fake responses for each request in the batch. # # Test with multiple activities to cover the bug described in # https://github.com/snarfed/bridgy/issues/22#issuecomment-56329848 : # util.CacheDict.get_multi() didn't originally handle generator args. batch = MIMEMultipart() for i, item in enumerate((COMMENT_GP, PLUSONER, RESHARER) * 2): msg = Message() msg.set_payload('HTTP/1.1 200 OK\n\r\n\r\n' + json.dumps({'items': [item]})) msg['Content-ID'] = '<response-abc+%d>' % (i + 1) batch.attach(msg) # as_string() must be called before get_boundary() to generate the # boundaries between parts, but can't be called again, so we capture the # result. batch_str = batch.as_string() gpe_1 = ACTIVITY_GP_EXTRAS gpe_2 = copy.deepcopy(gpe_1) gpe_2['id'] = '002' http_seq = http.HttpMockSequence([ ({ 'status': '200' }, json.dumps({'items': [gpe_1, gpe_2]})), ({ 'status': '200', 'content-type': 'multipart/mixed; boundary="%s"' % batch.get_boundary() }, batch_str), ({ 'status': '200' }, json.dumps({'items': [gpe_1, gpe_2]})), ]) self.auth_entity.http = lambda: http_seq ase_1 = ACTIVITY_AS_EXTRAS ase_2 = copy.deepcopy(ase_1) ase_2['id'] = tag_uri('002') ase_2['object']['tags'][0]['id'] = tag_uri('002_liked_by_222') ase_2['object']['tags'][1]['id'] = tag_uri('002_shared_by_444') cache = util.CacheDict() self.assert_equals([ase_1, ase_2], self.googleplus.get_activities(fetch_replies=True, fetch_likes=True, fetch_shares=True, cache=cache)) for id in '001', '002': for prefix in 'AGL ', 'AGS ': self.assertEquals(1, cache[prefix + id]) # no new extras, so another request won't fill them in as_1 = copy.deepcopy(ACTIVITY_AS) for field in 'replies', 'plusoners', 'resharers': as_1['object'][field] = {'totalItems': 1} as_2 = copy.deepcopy(as_1) as_2['id'] = tag_uri('002') self.assert_equals([as_1, as_2], self.googleplus.get_activities(fetch_replies=True, fetch_likes=True, fetch_shares=True, cache=cache))
def test_readfile_operations(self): class ITest(Interface): title = schema.TextLine() body = schema.Text() alsoProvides(ITest['body'], IPrimaryField) fti_mock = DexterityFTI(u'testtype') fti_mock.lookupSchema = Mock(return_value=ITest) fti_mock.behaviors = [ITestBehavior.__identifier__] self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype") item = Item('item') item.portal_type = 'testtype' readfile = DefaultReadFile(item) message = Message() message['title'] = 'Test title' message['foo'] = '10' message['bar'] = 'xyz' message.set_payload('<p>body</p>') from plone.rfc822 import constructMessageFromSchemata self.patch_global(constructMessageFromSchemata, return_value=message) body = b"""\ title: Test title foo: 10 bar: xyz Portal-Type: testtype <p>body</p>""" # iter # next self.assertEqual(body, readfile.read()) self.assertEqual(69, readfile.size()) self.assertEqual('utf-8', readfile.encoding) self.assertEqual(None, readfile.name) self.assertEqual('text/plain', readfile.mimeType) readfile.seek(2) self.assertEqual(2, readfile.tell()) self.assertEqual(b'tl', readfile.read(2)) self.assertEqual(4, readfile.tell()) readfile.seek(0, 2) self.assertEqual(69, readfile.tell()) readfile.seek(0) self.assertEqual(b'foo: 10\n', readfile.readlines()[1]) readfile.seek(0) self.assertEqual(b'foo: 10\n', readfile.readlines(100)[1]) readfile.seek(0) self.assertEqual(b'title: Test title\n', readfile.readline()) readfile.seek(0) self.assertEqual(b'title: Test title\n', readfile.readline(100)) readfile.seek(0) self.assertEqual(b'foo: 10\n', list(iter(readfile))[1]) self.assertEqual(False, readfile.closed) readfile.close()