def testNonASCIIAddrs(self): import os from email.mime import base import transaction from repoze.sendmail.delivery import QueuedMailDelivery from repoze.sendmail._compat import b from repoze.sendmail._compat import text_type delivery = QueuedMailDelivery(self.maildir_path) non_ascii = b('LaPe\xc3\xb1a').decode('utf-8') fromaddr = non_ascii + ' <*****@*****.**>' toaddrs = (non_ascii + ' <*****@*****.**>', ) message = base.MIMEBase('text', 'plain') message['From'] = fromaddr message['To'] = ','.join(toaddrs) delivery.send(fromaddr, toaddrs, message) self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'tmp'))) self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'new'))) transaction.commit() self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'tmp'))) self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'new'))) self.qp.send_messages() self.assertTrue(len(self.qp.mailer.sent_messages), 1) queued_fromaddr, queued_toaddrs, queued_message = ( self.qp.mailer.sent_messages[0]) self.assertEqual(queued_fromaddr, fromaddr) self.assertEqual(queued_toaddrs, toaddrs)
def attach(filename): '''Elkészíti a MIME részt, benne a fájlnévvel''' if not os.path.isfile(filename): return None ctype, encoding = mimetypes.guess_type(filename) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) attachContent = open(filename, 'rb').read() if maintype == 'text': msg = text.MIMEText(attachContent, _subtype=subtype) elif maintype == 'image': msg = image.MIMEImage(attachContent, _subtype=subtype) elif maintype == 'audio': msg = audio.MIMEAudio(attachContent, _subtype=subtype) else: msg = base.MIMEBase(maintype, subtype) msg.set_payload(attachContent) encoders.encode_base64(msg) msg.add_header('Content-Disposition', 'attachment', filename=filename) return msg
def send_mail(config, subject, message, files_to_attach): # unpack some config stuff email = config["email_config"]["email"] password = config["email_config"]["password"] email_name = config["email_config"]["name"] to_list = config["mailing_list"]["emails"] to_list_name = config["mailing_list"]["name"] # connect to gmail server = smtp('smtp.gmail.com', 587) server.ehlo() server.starttls() server.login(email, password) # build up the message msg = multipart.MIMEMultipart() msg.attach(text.MIMEText(message)) msg['From'] = email_name msg['To'] = to_list_name msg['Date'] = formatdate(localtime=True) msg['Subject'] = subject for f in files_to_attach: part = base.MIMEBase('application', "octet-stream") with open(f, "rb") as fp: part.set_payload(fp.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(f))) msg.attach(part) server.sendmail(email, to_list, msg.as_string()) server.quit()
def send_email(message_body, subject, sender, recipients, server, attachments=[], message_body_type='plain'): msg_root = mimemultipart.MIMEMultipart('mixed') msg_root['Date'] = email.utils.formatdate(localtime=True) msg_root['From'] = sender msg_root['To'] = ', '.join(recipients) msg_root['Subject'] = email.header.Header(subject, 'utf-8') msg_txt = mimetext.MIMEText(message_body, message_body_type, 'utf-8') msg_root.attach(msg_txt) for attachment in attachments: filename = os.path.basename(attachment) with open(attachment, 'rb') as f: msg_attach = mimebase.MIMEBase('application', 'octet-stream') msg_attach.set_payload(f.read()) email.encoders.encode_base64(msg_attach) msg_attach.add_header('Content-Disposition', 'attachment', filename=(email.header.Header( filename, 'utf-8').encode())) msg_root.attach(msg_attach) server.send_message(msg_root)
def mp_userdata_from_files(files, compress=False, multipart_mime=None): outer = multipart_mime or multipart.MIMEMultipart() mtypes = [] for i, fp in enumerate(files): mtype = _get_type_from_fp(fp) mtypes.append(mtype) maintype, subtype = mtype.split('/', 1) if maintype == 'text': # Note: we should handle calculating the charset msg = text.MIMEText(fp.read(), _subtype=subtype) fp.close() else: if hasattr(fp, 'name'): fp = open(fp.name, 'rb') msg = base.MIMEBase(maintype, subtype) msg.set_payload(fp.read()) fp.close() # Encode the payload using Base64 encoders.encode_base64(msg) # Set the filename parameter fname = getattr(fp, 'name', "sc_%d" % i) msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(fname)) outer.attach(msg) userdata = outer.as_string() if compress: s = StringIO.StringIO() gfile = gzip.GzipFile(fileobj=s, mode='w') gfile.write(userdata) gfile.close() s.seek(0) userdata = s.read() return userdata
def StoreBlob(self, form_item, creation): """Store form-item to blob storage. Args: form_item: FieldStorage instance that represents a specific form field. This instance should have a non-empty filename attribute, meaning that it is an uploaded blob rather than a normal form field. creation: Timestamp to associate with new blobs creation time. This parameter is provided so that all blobs in the same upload form can have the same creation date. Returns: datastore.Entity('__BlobInfo__') associated with the upload. """ main_type, sub_type = _SplitMIMEType(form_item.type) blob_key = self.__generate_blob_key() self.__blob_storage.StoreBlob(blob_key, form_item.file) content_type_formatter = base.MIMEBase(main_type, sub_type, **form_item.type_options) blob_entity = datastore.Entity('__BlobInfo__', name=str(blob_key)) blob_entity['content_type'] = ( content_type_formatter['content-type'].decode('utf-8')) blob_entity['creation'] = creation blob_entity['filename'] = form_item.filename.decode('utf-8') form_item.file.seek(0, 2) size = form_item.file.tell() form_item.file.seek(0) blob_entity['size'] = size datastore.Put(blob_entity) return blob_entity
def send_fic(url: str, email_address: str, password: str, kindle_email): port = 587 fic_filename = download_mobi_and_get_file_name(url) print('downloaded!') email = smtplib.SMTP('smtp.gmail.com', port) email.ehlo() email.starttls() # password = input('Password:'******'From'] = email_address msg['To'] = kindle_email msg['Subject'] = '' attachment = open(fic_filename, 'rb') p = base.MIMEBase('application', 'octet-stream') p.set_payload(attachment.read()) encoders.encode_base64(p) p.add_header('Content-Disposition', "attachment; filename= %s" % fic_filename) msg.attach(p) text = msg.as_string() email.sendmail(email_address, kindle_email, text) print('sent!') email.quit() attachment.close() os.remove(fic_filename)
def _getbundlemsgs(repo, sender, bundle, **opts): """Get the full email for sending a given bundle This function returns a list of "email" tuples (subject, content, None). The list is always one message long in that case. """ ui = repo.ui _charsets = mail._charsets(ui) subj = opts.get('subject') or prompt(ui, b'Subject:', b'A bundle for your repository') body = _getdescription(repo, b'', sender, **opts) msg = emimemultipart.MIMEMultipart() if body: msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test'))) datapart = emimebase.MIMEBase('application', 'x-mercurial-bundle') datapart.set_payload(bundle) bundlename = b'%s.hg' % opts.get('bundlename', b'bundle') datapart.add_header( 'Content-Disposition', 'attachment', filename=encoding.strfromlocal(bundlename), ) emailencoders.encode_base64(datapart) msg.attach(datapart) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) return [(msg, subj, None)]
def Send_email(file_name_list, email_text, recei_list): mail_info = { "from": "***@***.com", # 自己的邮箱账号 "to": "***@***.com", # 接收邮件的对方账号 "hostname": "smtp.exmail.qq.com", "username": "******", # 开通smtp服务的邮箱账号 "password": "******", # 开通smtp服务的对应密码 "mail_subject": "test", "mail_text": "hello, this is a test email, sended by python", "mail_encoding": "utf-8" } server = smtplib.SMTP_SSL(mail_info["hostname"], port=465) server.ehlo(mail_info["hostname"]) server.login(mail_info["username"], mail_info["password"]) # 仅smtp服务器需要验证时 # 构造MIMEMultipart对象做为根容器 main_msg = multipart.MIMEMultipart() # 构造MIMEText对象做为邮件显示内容并附加到根容器 text_msg = text.MIMEText(email_text, _charset="utf-8") main_msg.attach(text_msg) # 构造MIMEBase对象做为文件附件内容并附加到根容器 for file_name in file_name_list: ## 读入文件内容并格式化 [方式1] data = open(file_name, 'rb') ctype, encoding = mimetypes.guess_type(file_name) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) file_msg = base.MIMEBase(maintype, subtype) file_msg.set_payload(data.read()) data.close() email.encoders.encode_base64(file_msg) # 把附件编码 ## 设置附件头 basename = os.path.basename(file_name) file_msg.add_header('Content-Disposition', 'attachment', filename=basename, encoding='utf-8') main_msg.attach(file_msg) # 设置根容器属性 main_msg['From'] = mail_info['from'] main_msg['To'] = ';'.join(recei_list) main_msg['Subject'] = email_text main_msg['Date'] = email.utils.formatdate() # 得到格式化后的完整文本 fullText = main_msg.as_string() # 用smtp发送邮件 try: server.sendmail(mail_info['from'], recei_list, fullText) finally: server.quit()
def _handle_attachments(cls, outer, attachments): if type(attachments) == str: attrs = [attachments] elif type(attachments) == list: attrs = attachments else: attrs = [] for attached in attrs: if not os.path.isfile(attached): logger.warn('attached is not a file:%s' % attached) continue # Guess the content type based on the file's extension. Encoding # will be ignored, although we should check for simple things like # gzip'd or compressed files. ctype, encoding = mimetypes.guess_type(attached) if ctype is None or encoding is not None: # No guess could be made, or the file is encoded (compressed) # use a generic bag-of-bits type. ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) try: if maintype == 'text': with open(attached, 'rb') as fhandle: # Note: we should handle calculating the charset msg = text.MIMEText( fhandle.read(), _subtype=subtype ) elif maintype == 'image': with open(attached, 'rb') as fhandle: imgid = os.path.basename(attached) msg = image.MIMEImage( fhandle.read(), _subtype=subtype ) msg.add_header('Content-ID', imgid) elif maintype == 'audio': with open(attached, 'rb') as fhandle: msg = audio.MIMEAudio(fhandle.read(), _subtype=subtype) else: with open(attached, 'rb') as fhandle: msg = base.MIMEBase(maintype, subtype) msg.set_payload(fhandle.read()) # Encode the payload using Base64 encoders.encode_base64(msg) # Set the filename parameter msg.add_header( 'Content-Disposition', 'attachment', filename=os.path.basename(attached) ) outer.attach(msg) # pylint: disable=W0703 except Exception as exception: logger.warn( 'failed to attach %s, errmsg:%s. Will skip it' % ( attached, str(exception) ) )
def StoreBlob(self, form_item, creation): """Store form-item to blob storage. Args: form_item: FieldStorage instance that represents a specific form field. This instance should have a non-empty filename attribute, meaning that it is an uploaded blob rather than a normal form field. creation: Timestamp to associate with new blobs creation time. This parameter is provided so that all blobs in the same upload form can have the same creation date. Returns: datastore.Entity('__BlobInfo__') associated with the upload. """ main_type, sub_type = _SplitMIMEType(form_item.type) blob_key = self.__generate_blob_key() blob_file = form_item.file if 'Content-Transfer-Encoding' in form_item.headers: if form_item.headers['Content-Transfer-Encoding'] == 'base64': blob_file = cStringIO.StringIO( base64.urlsafe_b64decode(blob_file.read())) self.__blob_storage.StoreBlob(blob_key, blob_file) content_type_formatter = base.MIMEBase(main_type, sub_type, **form_item.type_options) blob_entity = datastore.Entity('__BlobInfo__', name=str(blob_key), namespace='') try: blob_entity['content_type'] = ( content_type_formatter['content-type'].decode('utf-8')) blob_entity['creation'] = creation blob_entity['filename'] = form_item.filename.decode('utf-8') except UnicodeDecodeError: raise InvalidMetadataError( 'The uploaded entity contained invalid UTF-8 metadata. This may be ' 'because the page containing the upload form was served with a ' 'charset other than "utf-8".') blob_file.seek(0) digester = hashlib.md5() while True: block = blob_file.read(1 << 20) if not block: break digester.update(block) blob_entity['md5_hash'] = digester.hexdigest() blob_entity['size'] = blob_file.tell() blob_file.seek(0) datastore.Put(blob_entity) return blob_entity
def SendNotificationEmail(subject, body, bugreport=None): """Sends an email with the specified subject and body. Also attach bugreport if bugreport location is provided as argument Args: subject: Subject of the email. body: Body of the email. bugreport: If provided, it will be attach to the email. """ if FLAGS.supress_notification_emails: logging.info("Email with subject '%s' has been supressed", subject) return try: # Assemble the message to send. recpient_address = FLAGS.notification_address message = multipart.MIMEMultipart("alternative") message["From"] = "Stress Test on %s" % socket.gethostname() message["To"] = recpient_address message["Subject"] = subject message.attach(text.MIMEText(body, "plain")) message.attach(text.MIMEText("<pre>%s</pre>" % body, "html")) if FLAGS.attach_bugreport and bugreport: # buildozer: disable=unused-variable ctype, _ = mimetypes.guess_type(bugreport) maintype, subtype = ctype.split("/", 1) with open(bugreport, "rb") as fp: att = base.MIMEBase(maintype, subtype) att.set_payload(fp.read()) encoders.encode_base64(att) att.add_header("Content-Disposition", "attachment", filename=bugreport) message.attach(att) # Send the message from our special account. server = smtplib.SMTP_SSL(FLAGS.email_smtp_server, FLAGS.email_smtp_port) server.login(FLAGS.email_sender_address, FLAGS.email_sender_password) server.sendmail(FLAGS.email_sender_address, recpient_address, message.as_string()) server.quit() logging.info("Email with subject '%s' has been sent", subject) except: # pylint:disable=bare-except logging.exception("Failed to send notification email")
def add_attachments(email: MIMEMultipart, attachments: list, max_MB: int = 25): '''Add the given attachments to the given email, up to the specified maximum size. ''' mime_consumer = {'text': text.MIMEText, 'image': image.MIMEImage, 'audio': audio.MIMEAudio } sz = len(bytes(email)) added = 0 count = 0 for f in attachments: print(sz / 1024 / 1024) margin = max_MB * 1024 * 1024 - sz if margin <= 100000: print(f'Message size limit reached. Added first {count} of {len(attachments)}') break mimetype, encoding = mimetypes.guess_type(f) if mimetype is None or encoding is not None: mimetype = 'application/octet-stream' main_type, sub_type = mimetype.split('/', 1) consumer = mime_consumer[main_type] if (main_type in mime_consumer) else ( application.MIMEApplication if (main_type == 'application' and sub_type == 'pdf') else None ) attachment = None if consumer is None: # Use the base mimetype attachment = base.MIMEBase(main_type, sub_type) with open(f, 'rb') as source: attachment.set_payload(source.read()) else: # Use the known conversion. print(f'Reading file of type {main_type}') with open(f, 'rb') as source: attachment = consumer(source.read(), _subtype=sub_type) encoders.encode_base64(attachment) attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(f)) if len(bytes(attachment)) >= margin: margin = 0 # Add your own "skip this file" or "these should be links from Drive" logic. else: added = len(bytes(attachment)) sz += added count += 1 email.attach(attachment) print(f'Email size is now ~{len(bytes(email)) / 1024 / 1024} MB')
def download(self, urls): """Faz o download de diários oficiais a partir de urls.""" intervalo = '{0}/{2} - {1}/{2}'.format( self.parâmetros_busca['edicao.dtInicio'], self.parâmetros_busca['edicao.dtFim'], self.parâmetros_busca['edicao.ano'], ) subject = 'Oi Igor! Nenhum diario foi encontrado nesse intervalo ({}) a partir da busca ' subject += '"{}" :/. Amanhã procuro novamente!' subject = subject.format(intervalo, self.parâmetros_busca['edicao.txtPesquisa']) email = mail.EmailMessage( 'Consulta Diário {}'.format(intervalo), subject, '*****@*****.**', [manager[-1] for manager in settings.MANAGERS]) for index, url in enumerate(urls): if index == 0: email.body = 'Oi Igor! Foram encontrados diários nesse intervalo ({}) a partir da' email.body += ' busca "{}"! :D. Segue em anexo:' email.body = email.body.format( intervalo, self.parâmetros_busca['edicao.txtPesquisa']) logger.info('Baixando diário a partir da url %s', url) diário_pdf = requests.get(url).content attachment = base.MIMEBase('application', 'pdf') attachment.set_payload(diário_pdf) encoders.encode_base64(attachment) nome_arquivo = '{}-{}'.format( self.parâmetros_busca['edicao.dtInicio'], self.parâmetros_busca['edicao.dtFim']) nome_arquivo = '[{}][{}]({}).pdf'.format( self.parâmetros_busca['edicao.txtPesquisa'], nome_arquivo, index).replace('/', '.') attachment.add_header('Content-Disposition', 'attachment', filename=nome_arquivo) email.attach(attachment) email.send()
def send_fic(self, fic : FanficDownloader): msg = multipart.MIMEMultipart() msg['From'] = self.email_address msg['To'] = self.kindle_email_address msg['Subject'] = '' # msg.attach(text.MIMEText('', 'plain')) fic.download_story() full_path = fic.file_path + '/' + fic.file_name # print(full_path) # print(fic.file_name) attachment = open(full_path, 'rb') p = base.MIMEBase('application', 'octet-stream') p.set_payload((attachment).read()) encoders.encode_base64(p) p.add_header('Content-Disposition', "attachment; filename= %s" % fic.file_name) msg.attach(p) text = msg.as_string() self.email.sendmail(self.email_address, self.kindle_email_address, text) self.email.quit()
def StoreBlob(self, form_item, creation): """Store form-item to blob storage. Args: form_item: FieldStorage instance that represents a specific form field. This instance should have a non-empty filename attribute, meaning that it is an uploaded blob rather than a normal form field. creation: Timestamp to associate with new blobs creation time. This parameter is provided so that all blobs in the same upload form can have the same creation date. Returns: datastore.Entity('__BlobInfo__') associated with the upload. """ main_type, sub_type = _SplitMIMEType(form_item["content_type"]) blob_key = self.__generate_blob_key() self.__blob_storage.StoreBlob(blob_key, cStringIO.StringIO(form_item["body"])) content_type_formatter = base.MIMEBase(main_type, sub_type) # **form_item.type_options) blob_entity = datastore.Entity('__BlobInfo__', name=str(blob_key), namespace='') try: blob_entity['content_type'] = ( content_type_formatter['content-type'].decode('utf-8')) blob_entity['creation'] = creation blob_entity['filename'] = form_item["filename"] #.decode('utf-8') except UnicodeDecodeError: raise InvalidMetadataError( 'The uploaded entity contained invalid UTF-8 metadata. This may be ' 'because the page containing the upload form was served with a ' 'charset other than "utf-8".') #form_item.file.seek(0, 2) #size = form_item.file.tell() #form_item.file.seek(0) blob_entity['size'] = len(form_item["body"]) datastore.Put(blob_entity) return blob_entity
def attachment_content(mail_config, subject, files): """ create base class for all the MIME-specific subclasses of Message by email.mime.base.MIMEBase class """ configfile = config.Config(mail_config) from_addr = configfile.__get_items__("smtp", "from_addr") to_addr = configfile.__get_items__("smtp", "to_addr") cc = configfile.__get_items__("smtp", "cc") msg = multipart.MIMEMultipart() msg['To'] = to_addr msg['From'] = from_addr msg['Subject'] = subject msg['CC'] = cc msg.attach( text.MIMEText( '<html><body><p>send by <a href="http://lfzyx.org">lfzyx</a></p>' '</body></html>', 'html', 'utf-8')) for file in files: with open(file, 'rb') as f: stream = base.MIMEBase('application', 'octet-stream', filename=file) stream.add_header('Content-Disposition', 'attachment', filename=file) stream.add_header('Content-ID', '<0>') stream.add_header('X-Attachment-Id', '0') stream.set_payload(f.read()) email.encoders.encode_base64(stream) msg.attach(stream) smtp_send(mail_config, msg)
def attach(self, filename, mime=None, charset=None, content=None): """Attach files to this message. Example:: msg.attach("me.png", mime="image/png") It also supports fake attachments:: msg.attach("fake.txt", mime="text/plain", content="gotcha") """ base = os.path.basename(filename) if content is None: fd = open(filename) content = fd.read() fd.close() elif not isinstance(content, str): raise TypeError("Don't know how to attach content: %s" % repr(content)) part = email_mime_base.MIMEBase("application", "octet-stream") part.set_payload(content) email_encoders.encode_base64(part) part.add_header("Content-Disposition", "attachment", filename=base) if mime is not None: part.set_type(mime) if charset is not None: part.set_charset(charset) if self.msg is None: self.msg = email_mime_multipart.MIMEMultipart() self.msg.attach(self.message) self.msg.attach(part)
def send_email(email_subject, email_body, email_sender='', email_to='', email_cc='', email_bcc='', files=None): # Pulling in the string value of the service key from the parameter with open(r'C:\Users\___.json') as f: service_account_info = json.loads(f.read()) # Define which scopes we're trying to access SCOPES = ['https://www.googleapis.com/auth/gmail.send'] # Setting up credentials using the gmail api credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=SCOPES) # This allows us to assign an alias account to the message so that the messages aren't coming from 'ServiceDriod-8328balh blah blah' delegated_credentials = credentials.with_subject(email_sender) # 'Building' the service instance using the credentials we've passed service = discovery.build(serviceName='gmail', version='v1', credentials=delegated_credentials) # Building out the email message = multipart.MIMEMultipart() message['to'] = email_to message['from'] = email_sender message['date'] = utils.formatdate(localtime=True) message['subject'] = email_subject message['cc'] = email_cc message['bcc'] = email_bcc message.attach(text.MIMEText(email_body, 'plain')) for f in files or []: f = f.strip(' ') mimetype, encoding = mimetypes.guess_type(f) # If the extension is not recognized it will return: (None, None) # If it's an .mp3, it will return: (audio/mp3, None) (None is for the encoding) # For an unrecognized extension we set mimetype to 'application/octet-stream' so it won't return None again. if mimetype is None or encoding is not None: mimetype = 'application/octet-stream' main_type, sub_type = mimetype.split('/', 1) # Creating the attachement: # This part is used to tell how the file should be read and stored (r, or rb, etc.) if main_type == 'text': print('text') with open(f, 'rb') as outfile: attachement = text.MIMEText(outfile.read(), _subtype=sub_type) elif main_type == 'image': print('image') with open(f, 'rb') as outfile: attachement = image.MIMEImage(outfile.read(), _subtype=sub_type) elif main_type == 'audio': print('audio') with open(f, 'rb') as outfile: attachement = audio.MIMEAudio(outfile.read(), _subtype=sub_type) elif main_type == 'application' and sub_type == 'pdf': with open(f, 'rb') as outfile: attachement = application.MIMEApplication(outfile.read(), _subtype=sub_type) else: attachement = base.MIMEBase(main_type, sub_type) with open(f, 'rb') as outfile: attachement.set_payload(outfile.read()) encoders.encode_base64(attachement) attachement.add_header('Content-Disposition', 'attachment', filename=os.path.basename(f)) message.attach(attachement) media_body = http.MediaIoBaseUpload(io.BytesIO(message.as_bytes()), mimetype='message/rfc822', resumable=True) body_metadata = {} # no thread, no labels in this example try: print('Uploading file...') response = service.users().messages().send( userId='me', body=body_metadata, media_body=media_body).execute() print(response) except errors.HttpError as error: print('An error occurred when sending the email:\n{}'.format(error))
def _GenerateMIMEMessage(self, form, boundary=None, max_bytes_per_blob=None, max_bytes_total=None, bucket_name=None): """Generate a new post from original form. Also responsible for storing blobs in the datastore. Args: form: Instance of cgi.FieldStorage representing the whole form derived from original post data. boundary: Boundary to use for resulting form. Used only in tests so that the boundary is always consistent. max_bytes_per_blob: The maximum size in bytes that any single blob in the form is allowed to be. max_bytes_total: The maximum size in bytes that the total of all blobs in the form is allowed to be. bucket_name: The name of the Google Storage bucket to uplad the file. Returns: A MIMEMultipart instance representing the new HTTP post which should be forwarded to the developers actual CGI handler. DO NOT use the return value of this method to generate a string unless you know what you're doing and properly handle folding whitespace (from rfc822) properly. Raises: UploadEntityTooLargeError: The upload exceeds either the max_bytes_per_blob or max_bytes_total limits. FilenameOrContentTypeTooLargeError: The filename or the content_type of the upload is larger than the allowed size for a string type in the datastore. """ message = multipart.MIMEMultipart('form-data', boundary) for name, value in form.headers.items(): if name.lower() not in STRIPPED_HEADERS: message.add_header(name, value) def IterateForm(): """Flattens form in to single sequence of cgi.FieldStorage instances. The resulting cgi.FieldStorage objects are a little bit irregular in their structure. A single name can have mulitple sub-items. In this case, the root FieldStorage object has a list associated with that field name. Otherwise, the root FieldStorage object just refers to a single nested instance. Lists of FieldStorage instances occur when a form has multiple values for the same name. Yields: cgi.FieldStorage irrespective of their nesting level. """ for key in sorted(form): form_item = form[key] if isinstance(form_item, list): for list_item in form_item: yield list_item else: yield form_item creation = self.__now_func() total_bytes_uploaded = 0 created_blobs = [] upload_too_large = False filename_too_large = False content_type_too_large = False for form_item in IterateForm(): disposition_parameters = {'name': form_item.name} if form_item.filename is None: variable = base.MIMEBase('text', 'plain') variable.set_payload(form_item.value) else: if not form_item.filename: continue disposition_parameters['filename'] = form_item.filename main_type, sub_type = _SplitMIMEType(form_item.type) form_item.file.seek(0, 2) content_length = form_item.file.tell() form_item.file.seek(0) total_bytes_uploaded += content_length if max_bytes_per_blob is not None: if max_bytes_per_blob < content_length: upload_too_large = True break if max_bytes_total is not None: if max_bytes_total < total_bytes_uploaded: upload_too_large = True break if form_item.filename is not None: if MAX_STRING_NAME_LENGTH < len(form_item.filename): filename_too_large = True break if form_item.type is not None: if MAX_STRING_NAME_LENGTH < len(form_item.type): content_type_too_large = True break blob_entity = self.StoreBlob(form_item, creation) created_blobs.append(blob_entity) variable = base.MIMEBase('message', 'external-body', access_type=blobstore.BLOB_KEY_HEADER, blob_key=blob_entity.key().name()) form_item.file.seek(0) digester = hashlib.md5() while True: block = form_item.file.read(1 << 20) if not block: break digester.update(block) blob_key = base64.urlsafe_b64encode(digester.hexdigest()) form_item.file.seek(0) external = base.MIMEBase(main_type, sub_type, **form_item.type_options) headers = dict(form_item.headers) headers['Content-Length'] = str(content_length) headers[blobstore.UPLOAD_INFO_CREATION_HEADER] = ( blobstore._format_creation(creation)) if bucket_name: headers[blobstore.CLOUD_STORAGE_OBJECT_HEADER] = ( '/gs/%s/fake-%s-%s' % (bucket_name, blob_entity.key().name(), blob_key)) headers['Content-MD5'] = blob_key for key, value in headers.iteritems(): external.add_header(key, value) external_disposition_parameters = dict(disposition_parameters) external_disposition_parameters['filename'] = form_item.filename if not external.get('Content-Disposition'): external.add_header('Content-Disposition', 'form-data', **external_disposition_parameters) variable.set_payload([external]) variable.add_header('Content-Disposition', 'form-data', **disposition_parameters) message.attach(variable) if upload_too_large or filename_too_large or content_type_too_large: for blob in created_blobs: datastore.Delete(blob) if upload_too_large: raise UploadEntityTooLargeError() elif filename_too_large: raise FilenameOrContentTypeTooLargeError('filename') else: raise FilenameOrContentTypeTooLargeError('content-type') return message
def send_i18n_digests(mlist, mboxfp): mbox = Mailbox(mboxfp) # Prepare common information (first lang/charset) lang = mlist.preferred_language lcset = Utils.GetCharSet(lang) lcset_out = Charset(lcset).output_charset or lcset # Common Information (contd) realname = mlist.real_name volume = mlist.volume issue = mlist.next_digest_number digestid = _('%(realname)s Digest, Vol %(volume)d, Issue %(issue)d') digestsubj = Header(digestid, lcset, header_name='Subject') # Set things up for the MIME digest. Only headers not added by # CookHeaders need be added here. # Date/Message-ID should be added here also. mimemsg = Message.Message() mimemsg['Content-Type'] = 'multipart/mixed' mimemsg['MIME-Version'] = '1.0' mimemsg['From'] = mlist.GetRequestEmail() mimemsg['Subject'] = digestsubj mimemsg['To'] = mlist.GetListEmail() mimemsg['Reply-To'] = mlist.GetListEmail() mimemsg['Date'] = formatdate(localtime=1) mimemsg['Message-ID'] = Utils.unique_message_id(mlist) # Set things up for the rfc1153 digest plainmsg = StringIO() rfc1153msg = Message.Message() rfc1153msg['From'] = mlist.GetRequestEmail() rfc1153msg['Subject'] = digestsubj rfc1153msg['To'] = mlist.GetListEmail() rfc1153msg['Reply-To'] = mlist.GetListEmail() rfc1153msg['Date'] = formatdate(localtime=1) rfc1153msg['Message-ID'] = Utils.unique_message_id(mlist) separator70 = '-' * 70 separator30 = '-' * 30 # In the rfc1153 digest, the masthead contains the digest boilerplate plus # any digest header. In the MIME digests, the masthead and digest header # are separate MIME subobjects. In either case, it's the first thing in # the digest, and we can calculate it now, so go ahead and add it now. mastheadtxt = Utils.maketext( 'masthead.txt', { 'real_name': mlist.real_name, 'got_list_email': mlist.GetListEmail(), 'got_listinfo_url': mlist.GetScriptURL('listinfo', absolute=1), 'got_request_email': mlist.GetRequestEmail(), 'got_owner_email': mlist.GetOwnerEmail(), }, mlist=mlist) # MIME masthead = text.MIMEText(mastheadtxt, _charset=lcset) masthead['Content-Description'] = digestid mimemsg.attach(masthead) # RFC 1153 print(mastheadtxt, file=plainmsg) print(file=plainmsg) # Now add the optional digest header but only if more than whitespace. if re.sub('\s', '', mlist.digest_header): headertxt = decorate(mlist, mlist.digest_header, _('digest header')) # MIME header = text.MIMEText(headertxt, _charset=lcset) header['Content-Description'] = _('Digest Header') mimemsg.attach(header) # RFC 1153 print(headertxt, file=plainmsg) print(file=plainmsg) # Now we have to cruise through all the messages accumulated in the # mailbox file. We can't add these messages to the plainmsg and mimemsg # yet, because we first have to calculate the table of contents # (i.e. grok out all the Subjects). Store the messages in a list until # we're ready for them. # # Meanwhile prepare things for the table of contents toc = StringIO() print(_("Today's Topics:\n"), file=toc) # Now cruise through all the messages in the mailbox of digest messages, # building the MIME payload and core of the RFC 1153 digest. We'll also # accumulate Subject: headers and authors for the table-of-contents. messages = [] msgcount = 0 msg = next(mbox) while msg is not None: if msg == '': # It was an unparseable message msg = next(mbox) continue msgcount += 1 messages.append(msg) # Get the Subject header msgsubj = msg.get('subject', _('(no subject)')) subject = Utils.oneline(msgsubj, lcset) # Don't include the redundant subject prefix in the toc mo = re.match('(re:? *)?(%s)' % re.escape(mlist.subject_prefix), subject, re.IGNORECASE) if mo: subject = subject[:mo.start(2)] + subject[mo.end(2):] username = '' addresses = getaddresses([Utils.oneline(msg.get('from', ''), lcset)]) # Take only the first author we find if isinstance(addresses, list) and addresses: username = addresses[0][0] if not username: username = addresses[0][1] if username: username = '******' % username # Put count and Wrap the toc subject line wrapped = Utils.wrap('%2d. %s' % (msgcount, subject), 65) slines = wrapped.split('\n') # See if the user's name can fit on the last line if len(slines[-1]) + len(username) > 70: slines.append(username) else: slines[-1] += username # Add this subject to the accumulating topics first = True for line in slines: if first: print(' ', line, file=toc) first = False else: print(' ', line.lstrip(), file=toc) # We do not want all the headers of the original message to leak # through in the digest messages. For this phase, we'll leave the # same set of headers in both digests, i.e. those required in RFC 1153 # plus a couple of other useful ones. We also need to reorder the # headers according to RFC 1153. Later, we'll strip out headers for # for the specific MIME or plain digests. keeper = {} all_keepers = {} for header in (mm_cfg.MIME_DIGEST_KEEP_HEADERS + mm_cfg.PLAIN_DIGEST_KEEP_HEADERS): all_keepers[header] = True all_keepers = list(all_keepers.keys()) for keep in all_keepers: keeper[keep] = msg.get_all(keep, []) # Now remove all unkempt headers :) for header in list(msg.keys()): del msg[header] # And add back the kept header in the RFC 1153 designated order for keep in all_keepers: for field in keeper[keep]: msg[keep] = field # And a bit of extra stuff msg['Message'] = repr(msgcount) # Get the next message in the digest mailbox msg = next(mbox) # Now we're finished with all the messages in the digest. First do some # sanity checking and then on to adding the toc. if msgcount == 0: # Why did we even get here? return toctext = to_cset_out(toc.getvalue(), lcset) # MIME tocpart = text.MIMEText(toctext, _charset=lcset) tocpart['Content-Description'] = _( "Today's Topics (%(msgcount)d messages)") mimemsg.attach(tocpart) # RFC 1153 print(toctext, file=plainmsg) print(file=plainmsg) # For RFC 1153 digests, we now need the standard separator print(separator70, file=plainmsg) print(file=plainmsg) # Now go through and add each message mimedigest = base.MIMEBase('multipart', 'digest') mimemsg.attach(mimedigest) first = True for msg in messages: # MIME. Make a copy of the message object since the rfc1153 # processing scrubs out attachments. mimedigest.attach(message.MIMEMessage(copy.deepcopy(msg))) # rfc1153 if first: first = False else: print(separator30, file=plainmsg) print(file=plainmsg) # Use Mailman.Handlers.Scrubber.process() to get plain text try: msg = scrubber(mlist, msg) except Errors.DiscardMessage: print(_('[Message discarded by content filter]'), file=plainmsg) continue # Honor the default setting for h in mm_cfg.PLAIN_DIGEST_KEEP_HEADERS: if msg[h]: uh = Utils.wrap('%s: %s' % (h, Utils.oneline(msg[h], lcset))) uh = '\n\t'.join(uh.split('\n')) print(uh, file=plainmsg) print(file=plainmsg) # If decoded payload is empty, this may be multipart message. # -- just stringfy it. payload = msg.get_payload(decode=True) \ or msg.as_string().split('\n\n',1)[1] mcset = msg.get_content_charset('') if mcset and mcset != lcset and mcset != lcset_out: try: payload = str(payload, mcset, 'replace').encode(lcset, 'replace') except (UnicodeError, LookupError): # TK: Message has something unknown charset. # _out means charset in 'outer world'. payload = str(payload, lcset_out, 'replace').encode(lcset, 'replace') print(payload, file=plainmsg) if not payload.endswith('\n'): print(file=plainmsg) # Now add the footer but only if more than whitespace. if re.sub('\s', '', mlist.digest_footer): footertxt = decorate(mlist, mlist.digest_footer, _('digest footer')) # MIME footer = text.MIMEText(footertxt, _charset=lcset) footer['Content-Description'] = _('Digest Footer') mimemsg.attach(footer) # RFC 1153 # MAS: There is no real place for the digest_footer in an RFC 1153 # compliant digest, so add it as an additional message with # Subject: Digest Footer print(separator30, file=plainmsg) print(file=plainmsg) print('Subject: ' + _('Digest Footer'), file=plainmsg) print(file=plainmsg) print(footertxt, file=plainmsg) print(file=plainmsg) print(separator30, file=plainmsg) print(file=plainmsg) # Do the last bit of stuff for each digest type signoff = _('End of ') + digestid # MIME # BAW: This stuff is outside the normal MIME goo, and it's what the old # MIME digester did. No one seemed to complain, probably because you # won't see it in an MUA that can't display the raw message. We've never # got complaints before, but if we do, just wax this. It's primarily # included for (marginally useful) backwards compatibility. mimemsg.postamble = signoff # rfc1153 print(signoff, file=plainmsg) print('*' * len(signoff), file=plainmsg) # Do our final bit of housekeeping, and then send each message to the # outgoing queue for delivery. mlist.next_digest_number += 1 virginq = get_switchboard(mm_cfg.VIRGINQUEUE_DIR) # Calculate the recipients lists plainrecips = [] mimerecips = [] drecips = mlist.getDigestMemberKeys() + list(mlist.one_last_digest.keys()) for user in mlist.getMemberCPAddresses(drecips): # user might be None if someone who toggled off digest delivery # subsequently unsubscribed from the mailing list. Also, filter out # folks who have disabled delivery. if user is None or mlist.getDeliveryStatus(user) != ENABLED: continue # Otherwise, decide whether they get MIME or RFC 1153 digests if mlist.getMemberOption(user, mm_cfg.DisableMime): plainrecips.append(user) else: mimerecips.append(user) # Zap this since we're now delivering the last digest to these folks. mlist.one_last_digest.clear() # MIME virginq.enqueue(mimemsg, recips=mimerecips, listname=mlist.internal_name(), isdigest=True) # RFC 1153 rfc1153msg.set_payload(to_cset_out(plainmsg.getvalue(), lcset), lcset) virginq.enqueue(rfc1153msg, recips=plainrecips, listname=mlist.internal_name(), isdigest=True)
def send_email(email_sender='me', email_to='', email_subject='', email_body_html='', email_cc='', email_bcc='', files=None): credentials = get_credentials() service = discovery.build(serviceName='gmail', version='v1', credentials=credentials) message = multipart.MIMEMultipart() message['to'] = email_to message['from'] = email_sender message['date'] = utils.formatdate(localtime=True) message['subject'] = email_subject message['cc'] = email_cc message['bcc'] = email_bcc message.attach(text.MIMEText(email_body_html, 'html')) for f in files or []: f = f.strip(' ') mimetype, encoding = mimetypes.guess_type(f) if mimetype is None or encoding is not None: mimetype = 'application/octet-stream' main_type, sub_type = mimetype.split('/', 1) if main_type == 'text': with open(f, 'rb') as outfile: attachement = text.MIMEText(outfile.read(), _subtype=sub_type) elif main_type == 'image': with open(f, 'rb') as outfile: attachement = image.MIMEImage(outfile.read(), _subtype=sub_type) elif main_type == 'audio': with open(f, 'rb') as outfile: attachement = audio.MIMEAudio(outfile.read(), _subtype=sub_type) elif main_type == 'application' and sub_type == 'pdf': with open(f, 'rb') as outfile: attachement = application.MIMEApplication(outfile.read(), _subtype=sub_type) else: attachement = base.MIMEBase(main_type, sub_type) with open(f, 'rb') as outfile: attachement.set_payload(outfile.read()) encoders.encode_base64(attachement) attachement.add_header('Content-Disposition', 'attachment', filename=os.path.basename(f)) message.attach(attachement) msg_bytes = message.as_bytes() print(f"Message size: {format_size(len(msg_bytes))}") media_body = http.MediaIoBaseUpload(io.BytesIO(msg_bytes), mimetype='message/rfc822', resumable=True) body_metadata = {} print('Sending...') try: response = service.users().messages().send( userId='me', body=body_metadata, media_body=media_body).execute() print(response) except errors.HttpError as error: print('Error:\n{}'.format(error))
gmail_password = "******" mail_to = "*****@*****.**" subject = "Email from python" body = "This email from python." file_path = "./test.tar.gz" encoding = "utf-8" msg = multipart.MIMEMultipart() msg["Subject"] = Header(subject, encoding) msg["To"] = mail_to msg["From"] = gmail_account msg.attach(text.MIMEText(body, "plain", encoding)) attach = base.MIMEBase("application", "tar.gz") with open(file_path, "br") as f: attach.set_payload(f.read()) encoders.encode_base64(attach) attach.add_header( "Content-Disposition", "attachment", filename="attachment.tar.gz" ) msg.attach(attach) server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context=ssl.create_default_context()) server.login(gmail_account, gmail_password) server.send_message(msg)
def _GenerateMIMEMessage(self, form, boundary=None): """Generate a new post from original form. Also responsible for storing blobs in the datastore. Args: form: Instance of cgi.FieldStorage representing the whole form derived from original post data. boundary: Boundary to use for resulting form. Used only in tests so that the boundary is always consistent. Returns: A MIMEMultipart instance representing the new HTTP post which should be forwarded to the developers actual CGI handler. DO NOT use the return value of this method to generate a string unless you know what you're doing and properly handle folding whitespace (from rfc822) properly. """ message = multipart.MIMEMultipart('form-data', boundary) for name, value in form.headers.items(): if name.lower() not in STRIPPED_HEADERS: message.add_header(name, value) def IterateForm(): """Flattens form in to single sequence of cgi.FieldStorage instances. The resulting cgi.FieldStorage objects are a little bit irregular in their structure. A single name can have mulitple sub-items. In this case, the root FieldStorage object has a list associated with that field name. Otherwise, the root FieldStorage object just refers to a single nested instance. Lists of FieldStorage instances occur when a form has multiple values for the same name. Yields: cgi.FieldStorage irrespective of their nesting level. """ for key in sorted(form): form_item = form[key] if isinstance(form_item, list): for list_item in form_item: yield list_item else: yield form_item creation = self.__now_func() for form_item in IterateForm(): disposition_parameters = {'name': form_item.name} if form_item.filename is None: variable = base.MIMEBase('text', 'plain') variable.set_payload(form_item.value) else: disposition_parameters['filename'] = form_item.filename main_type, sub_type = _SplitMIMEType(form_item.type) blob_entity = self.StoreBlob(form_item, creation) variable = base.MIMEBase('message', 'external-body', access_type=blobstore.BLOB_KEY_HEADER, blob_key=blob_entity.key().name()) form_item.file.seek(0, 2) content_length = form_item.file.tell() form_item.file.seek(0) external = base.MIMEBase(main_type, sub_type, **form_item.type_options) headers = dict(form_item.headers) headers['Content-Length'] = str(content_length) headers[ blobstore.UPLOAD_INFO_CREATION_HEADER] = _FormatDateTime( creation) for key, value in headers.iteritems(): external.add_header(key, value) external_disposition_parameters = dict(disposition_parameters) external_disposition_parameters[ 'filename'] = form_item.filename if not external.get('Content-Disposition'): external.add_header('Content-Disposition', 'form-data', **external_disposition_parameters) variable.set_payload([external]) variable.add_header('Content-Disposition', 'form-data', **disposition_parameters) message.attach(variable) return message
def execute(sender, password, recipients, subject, body, attachments): print sender, password, recipients, subject, body, attachments backslash_map = { '\a': r'\a', '\b': r'\b', '\f': r'\f', '\n': r'\n', '\r': r'\r', '\t': r'\t', '\v': r'\v' } for key, value in backslash_map.items(): recipients = recipients.replace(key, value) recipients = recipients.replace('\\', '\\\\') f = open(recipients, 'r') recipients = ' '.join(f.readlines()) msg = multipart.MIMEMultipart() msg['From'] = sender msg['To'] = recipients msg['Subject'] = subject msg.attach(text.MIMEText(body, 'plain')) for filename in attachments: f = filename for key, value in backslash_map.items(): f = f.replace(key, value) f = f.replace('\\', '\\\\') part = base.MIMEBase('application', "octet-stream") part.set_payload(open(f, "rb").read()) encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f)) msg.attach(part) try: server = smtplib.SMTP('smtp.gmail.com', 587) server.set_debuglevel(False) server.starttls() server.login(sender, password) except socket.gaierror: print "Check your Internet Connection" return 2 except smtplib.SMTPAuthenticationError: print "Invalid Username or Password" return 3 except: print "Login Failed" return 4 try: server.sendmail(msg['From'], recipients.split(), msg.as_string()) print 'Email Sent Successfully' server.quit() return 1 except: print "Email Not Sent" return 0