def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=None, sendername=None, receivername=None): # attachment format, each is a tuple of (name, mimetype,contents) # content should be *binary* and not base64 encoded, since we need to # use the base64 routines from the email library to get a properly # formatted output message msg = MIMEMultipart() msg['Subject'] = subject msg['To'] = _encoded_email_header(receivername, receiver) msg['From'] = _encoded_email_header(sendername, sender) msg['Date'] = formatdate(localtime=True) msg.attach(MIMEText(msgtxt, _charset='utf-8')) if attachments: for filename, contenttype, content in attachments: main,sub = contenttype.split('/') part = MIMENonMultipart(main,sub) part.set_payload(content) part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename) encoders.encode_base64(part) msg.attach(part) # Just write it to the queue, so it will be transactionally rolled back QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string()).save() # Any bcc is just entered as a separate email if bcc: QueuedMail(sender=sender, receiver=bcc, fullmsg=msg.as_string()).save()
def addAttachment(self, attachment, filename, mimetype=None): if not mimetype: mimetype = mimetypes.guess_type(filename)[0] if not mimetype: raise Exception("could not determine MIME type for ", filename) if "/" in mimetype: major, minor = mimetype.split("/") else: major = mimetype minor = None if not self.hasAttachments: body = self.msg.set_payload() newMsg = MIMEMultipart() newMsg.attach(MIMEText(body)) for header, value in self.msg.items(): newMsg[header] = value self.msg = newMsg self.hasAttachments = True subMessage = MIMENonMultipart(major, minor, name=filename) subMessage.set_payload(attachment) if major == "text": encoder = Encoders.encode_quopri else: encoder = Encoders.encode_base64 encoder(subMessage) self.msg.attach(subMessage)
def __init__(self, _audiodata, _subtype = None, _encoder = encoders.encode_base64, **_params): """Create an audio/* type MIME document. _audiodata is a string containing the raw audio data. If this data can be decoded by the standard Python `sndhdr' module, then the subtype will be automatically included in the Content-Type header. Otherwise, you can specify the specific audio subtype via the _subtype parameter. If _subtype is not given, and no subtype can be guessed, a TypeError is raised. _encoder is a function which will perform the actual encoding for transport of the image data. It takes one argument, which is this Image instance. It should use get_payload() and set_payload() to change the payload to the encoded form. It should also add any Content-Transfer-Encoding or other headers to the message as necessary. The default encoding is Base64. Any additional keyword arguments are passed to the base class constructor, which turns them into parameters on the Content-Type header. """ if _subtype is None: _subtype = _whatsnd(_audiodata) if _subtype is None: raise TypeError('Could not find audio MIME subtype') MIMENonMultipart.__init__(self, 'audio', _subtype, **_params) self.set_payload(_audiodata) _encoder(self) return
def __init__(self, message): MIMENonMultipart.__init__(self, 'text', 'plain', charset='utf-8') utf8qp = email.charset.Charset('utf-8') utf8qp.body_encoding = email.charset.QP payload = message.get_payload(decode=True) self.set_payload(payload, charset=utf8qp)
def as_message(self, escape_addresses=True): # http://wordeology.com/computer/how-to-send-good-unicode-email-with-python.html # http://stackoverflow.com/questions/31714221/how-to-send-an-email-with-quoted # http://stackoverflow.com/questions/9403265/how-do-i-use-python/9509718#9509718 charset = Charset('utf-8') charset.header_encoding = QP charset.body_encoding = QP msg = MIMEMultipart() # Headers unixfrom = "From %s %s" % ( self.sender.address, self.archived_date.strftime("%c")) header_from = self.sender.address if self.sender.name and self.sender.name != self.sender.address: header_from = "%s <%s>" % (self.sender.name, header_from) header_to = self.mailinglist.name if escape_addresses: header_from = header_from.replace("@", " at ") header_to = header_to.replace("@", " at ") unixfrom = unixfrom.replace("@", " at ") msg.set_unixfrom(unixfrom) headers = ( ("From", header_from), ("To", header_to), ("Subject", self.subject), ) for header_name, header_value in headers: if not header_value: continue try: msg[header_name] = header_value.encode('ascii') except UnicodeEncodeError: msg[header_name] = Header( header_value.encode('utf-8'), charset).encode() tz = get_fixed_timezone(self.timezone) header_date = self.date.astimezone(tz).replace(microsecond=0) # Date format: http://tools.ietf.org/html/rfc5322#section-3.3 msg["Date"] = header_date.strftime("%a, %d %b %Y %H:%M:%S %z") msg["Message-ID"] = "<%s>" % self.message_id if self.in_reply_to: msg["In-Reply-To"] = self.in_reply_to # Body content = self.ADDRESS_REPLACE_RE.sub(r"\1(a)\2", self.content) # Don't use MIMEText, it won't encode to quoted-printable textpart = MIMENonMultipart("text", "plain", charset='utf-8') textpart.set_payload(content, charset=charset) msg.attach(textpart) # Attachments for attachment in self.attachments.order_by("counter"): mimetype = attachment.content_type.split('/', 1) part = MIMEBase(mimetype[0], mimetype[1]) part.set_payload(attachment.content) encode_base64(part) part.add_header('Content-Disposition', 'attachment', filename=attachment.name) msg.attach(part) return msg
def _execute(self, http, order, requests): """Serialize batch request, send to server, process response. Args: http: httplib2.Http, an http object to be used to make the request with. order: list, list of request ids in the order they were added to the batch. request: list, list of request objects to send. Raises: httplib2.Error if a transport error has occured. apiclient.errors.BatchError if the response is the wrong format. """ message = MIMEMultipart('mixed') # Message should not write out it's own headers. setattr(message, '_write_headers', lambda self: None) # Add all the individual requests. for request_id in order: request = requests[request_id] msg = MIMENonMultipart('application', 'http') msg['Content-Transfer-Encoding'] = 'binary' msg['Content-ID'] = self._id_to_header(request_id) body = self._serialize_request(request) msg.set_payload(body) message.attach(msg) body = message.as_string() headers = {} headers['content-type'] = ('multipart/mixed; ' 'boundary="%s"') % message.get_boundary() resp, content = http.request(self._batch_uri, 'POST', body=body, headers=headers) if resp.status >= 300: raise HttpError(resp, content, self._batch_uri) # Now break out the individual responses and store each one. boundary, _ = content.split(None, 1) # Prepend with a content-type header so FeedParser can handle it. header = 'content-type: %s\r\n\r\n' % resp['content-type'] for_parser = header + content parser = FeedParser() parser.feed(for_parser) mime_response = parser.close() if not mime_response.is_multipart(): raise BatchError("Response not in multipart/mixed format.", resp, content) for part in mime_response.get_payload(): request_id = self._header_to_id(part['Content-ID']) headers, content = self._deserialize_response(part.get_payload()) self._responses[request_id] = (headers, content)
def post(self, request): context = self.get_context_data() form, user = context['form'], request.user if not form.is_valid(): return self.get(request) s = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT) s.starttls() if settings.EMAIL_HOST_USER: s.login(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD) sender = "%s %s (via OxPoints Editor) <%s>" % (user.first_name, user.last_name, user.email) recipients = ['%s <%s>' % manager for manager in settings.MANAGERS] msg = MIMEMultipart() msg['Subject'] = form.cleaned_data['subject'] msg['From'] = sender msg['To'] = ', '.join(recipients) msg.attach(MIMEText(form.cleaned_data['message'], 'plain')) if request.FILES.get('related_file'): related_file = request.FILES['related_file'] attachment = MIMENonMultipart(*related_file.content_type.split('/', 1)) attachment.add_header('Content-Disposition', 'attachment', filename=related_file.name) attachment.set_payload(related_file.read()) msg.attach(attachment) s.sendmail(sender, recipients, msg.as_string()) return redirect(reverse('core:request') + '?sent=true')
def __init__(self, _text, _subtype='plain', _charset=None): """Create a text/* type MIME document. _text is the string for this message object. _subtype is the MIME sub content type, defaulting to "plain". _charset is the character set parameter added to the Content-Type header. This defaults to "us-ascii". Note that as a side-effect, the Content-Transfer-Encoding header will also be set. """ # If no _charset was specified, check to see if there are non-ascii # characters present. If not, use 'us-ascii', otherwise use utf-8. # XXX: This can be removed once #7304 is fixed. if _charset is None: try: _text.encode('us-ascii') _charset = 'us-ascii' except UnicodeEncodeError: _charset = 'utf-8' MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) self.set_payload(_text, _charset)
def __init__(self, _text, _subtype="plain", _charset="utf-8"): if not isinstance(_charset, Charset): _charset = Charset(_charset) if isinstance(_text, unicode): _text = _text.encode(_charset.input_charset) MIMENonMultipart.__init__(self, "text", _subtype, **{"charset": _charset.input_charset}) self.set_payload(_text, _charset)
def sendmail(text, sender, subject, archive=None): if not c.has_option('commitmsg', 'destination'): return if c.has_option('commitmsg', 'replyto'): pieces = [] for p in c.get('commitmsg', 'replyto').split(','): pp = p.strip() if pp == '$committer': if sender: pieces.append(sender.strip()) # Don't add fallback sender as committer else: pieces.append(pp) replyto = ', '.join(pieces) else: replyto = None if not sender: # No sender specified, so use fallback sender = cfg.get('commitmsg', 'fallbacksender') (sender_name, sender_address) = email.utils.parseaddr(sender) if c.has_option('commitmsg', 'forcesenderaddr'): sender_address = c.get('commitmsg', 'forcesenderaddr') if sender_name: fullsender = "{0} <{1}>".format(sender_name, sender_address) else: fullsender = sender_address for m in c.get('commitmsg', 'destination').split(','): msg = MIMEMultipart() msg['From'] = fullsender msg['To'] = m msg['Subject'] = subject if replyto: msg['Reply-To'] = replyto # Don't specify utf8 when doing debugging, because that will encode the output # as base64 which is completely useless on the console... if debug == 1: msg.attach(MIMEText(text)) else: msg.attach(MIMEText(text, _charset='utf-8')) if archive: part = MIMENonMultipart('application', 'x-gzip') part.set_payload(archive) part.add_header('Content-Disposition', 'attachment; filename="archive.tar.gz"') encoders.encode_base64(part) msg.attach(part) allmail.append({ 'sender': sender_address, 'to': m, 'msg': msg, })
def __init__(self, _imagedata, _subtype = None, _encoder = encoders.encode_base64, **_params): if _subtype is None: _subtype = imghdr.what(None, _imagedata) if _subtype is None: raise TypeError('Could not guess image MIME subtype') MIMENonMultipart.__init__(self, 'image', _subtype, **_params) self.set_payload(_imagedata) _encoder(self)
def __init__(self, _text, _subtype='plain', _charset='utf-8'): if not isinstance(_charset, Charset): _charset = Charset(_charset) if isinstance(_text,unicode): _text = _text.encode(_charset.input_charset) MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset.input_charset}) self.set_payload(_text, _charset)
def __init__(self, _audiodata, _subtype = None, _encoder = encoders.encode_base64, **_params): if _subtype is None: _subtype = _whatsnd(_audiodata) if _subtype is None: raise TypeError('Could not find audio MIME subtype') MIMENonMultipart.__init__(self, 'audio', _subtype, **_params) self.set_payload(_audiodata) _encoder(self)
def _send_batch_request(self, requests): """Sends a batch of requests to the server and processes the HTTP responses. Args: requests: List of GoogleComputeEngineBase.API_REQUEST named tuples. Must contain <= MAX_BATCH_SIZE elements. Raises: ValueError: If requests has more than MAX_BATCH_SIZE elements. Returns: List of GoogleComputeEngineBase.BATCH_RESPONSE named tuples, one for each element of request parameter. """ if len(requests) > MAX_BATCH_SIZE: raise ValueError('Too many requests provided' '(maximum is {0})'.format(MAX_BATCH_SIZE)) batch = _BatchApiRequest() base = urlparse.urlsplit(self.base_url) base_path = base.path.rstrip('/') for i, request in enumerate(requests): msg = MIMENonMultipart('application', 'http') msg.add_header('Content-ID', '<{0}>'.format(i)) msg.set_payload(self._serialize_batch_api_request(base_path, request)) batch.attach(msg) batch_string = batch.as_string() content_type = 'multipart/mixed; boundary="{0}"'.format( batch.get_boundary()) url = urlparse.urlunsplit((base.scheme, base.netloc, 'batch', self._create_url_query(None), None)) response, data = self._send_request(url, 'POST', batch_string, content_type) if response.status >= 300: error = gce.GceError( message=response.reason, status=response.status) return [error] * len(requests) # Return all errors. elif not data: error = gce.GceError( message='Server returned no data', status=response.status) return [error] * len(requests) # Return all errors. # Process successful response. data = 'content-type: {0}\r\n\r\n'.format(response['content-type']) + data parser = FeedParser() parser.feed(data) response = parser.close() responses = [] for part in response.get_payload(): responses.append(( int(RESPONSE_ID_REGEX.match(part['Content-ID']).group(1)), self._parse_batch_api_response(part.get_payload()))) responses.sort(key=lambda r: r[0]) return [r[1] for r in responses]
def _add_attachments(self, mime): for attachment in getattr(self, '_attachments', []): major, sub = attachment['content-type'].split('/') attachment_mime = MIMENonMultipart(major, sub) base64_attachment_file = binascii.b2a_base64(attachment['raw']) attachment_mime.set_payload(base64_attachment_file) attachment_mime['Content-Disposition'] = 'attachment; filename="%s"' % attachment['name'] attachment_mime['Content-Transfer-Encoding'] = 'base64' mime.attach(attachment_mime)
def __init__(self, text, charset='utf-8'): """ Based on email.mime.text.MIMEText but adds format=flowed to the content type. Also defaults to UTF-8. """ MIMENonMultipart.__init__(self, 'text', 'plain', charset=charset, format='flowed') self.set_payload(text, charset)
def __init__(self, _text, _subtype='plain', _charset=None): if _charset is None: try: _text.encode('us-ascii') _charset = 'us-ascii' except UnicodeEncodeError: _charset = 'utf-8' MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) self.set_payload(_text, _charset)
def test_raw_with_attachment_data(self): input_mail = InputMail.from_dict(with_attachment_mail_dict(), from_address='pixelated@org') attachment = MIMENonMultipart('text', 'plain', Content_Disposition='attachment; filename=ayoyo.txt') attachment.set_payload('Hello World') mail = MIMEMultipart() mail.attach(attachment) part_one = 'Content-Type: text/plain\nMIME-Version: 1.0\nContent-Disposition: attachment; filename="ayoyo.txt"\nContent-Transfer-Encoding: base64\n\n' part_two = 'Content-Type: text/html\nMIME-Version: 1.0\nContent-Disposition: attachment; filename="hello.html"\nContent-Transfer-Encoding: base64\n\n' self.assertRegexpMatches(input_mail.raw, part_one) self.assertRegexpMatches(input_mail.raw, part_two)
def __init__(self, _text, _subtype = 'plain', _charset = 'us-ascii'): """Create a text/* type MIME document. _text is the string for this message object. _subtype is the MIME sub content type, defaulting to "plain". _charset is the character set parameter added to the Content-Type header. This defaults to "us-ascii". Note that as a side-effect, the Content-Transfer-Encoding header will also be set. """ MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) self.set_payload(_text, _charset)
def upload(self, filename): name = os.path.basename(filename) size = os.path.getsize(filename) cype = guess_type(name) if not cype or not cype[0]: cype = "text/plain" else: cype = cype[0] url = ("https://www.googleapis.com/upload/drive/v2/files?" "uploadType=multipart") message = MIMEMultipart('mixed') # Message should not write out it's own headers. setattr(message, '_write_headers', lambda self: None) msg = MIMENonMultipart('application', 'json; charset=UTF-8') msg.set_payload(json.dumps({"title": name, #.replace("'", r"\'"), "mimeType": cype})) message.attach(msg) msg = MIMENonMultipart(*cype.split('/')) msg.add_header("Content-Transfer-Encoding", "binary") msg.set_payload(open(filename).read()) message.attach(msg) body = message.as_string() bd = message.get_boundary() hd = {"Content-Type": 'multipart/related; boundary="%s"' % bd} res = self.auth_http("POST", url, body, hd) ret = res.read() pprint(ret) return
def _attachment_to_cdoc(self, content, content_type, encoder=encoders.encode_base64): major, sub = content_type.split('/') attachment = MIMENonMultipart(major, sub) attachment.set_payload(content) encoder(attachment) attachment.add_header('Content-Disposition', 'attachment', filename='does_not_matter.txt') pseudo_mail = MIMEMultipart() pseudo_mail.attach(attachment) tmp_mail = SoledadMailAdaptor().get_msg_from_string(MessageClass=Message, raw_msg=pseudo_mail.as_string()) cdoc = tmp_mail.get_wrapper().cdocs[1] return cdoc
def _generate_MIME_part(key, content, keytype, headers): if not keytype: try: content.encode("ascii") keytype = ("text", "plain") except UnicodeError: keytype = ("application", "octet-stream") submsg = MIMENonMultipart(*keytype) content_headers = {'name': key} if headers: content_headers.update(headers) submsg.add_header("Content-disposition", "form-data", **content_headers) submsg.set_payload(content) return submsg
def __init__(self, _msg, _subtype = 'rfc822'): """Create a message/* type MIME document. _msg is a message object and must be an instance of Message, or a derived class of Message, otherwise a TypeError is raised. Optional _subtype defines the subtype of the contained message. The default is "rfc822" (this is defined by the MIME standard, even though the term "rfc822" is technically outdated by RFC 2822). """ MIMENonMultipart.__init__(self, 'message', _subtype) if not isinstance(_msg, message.Message): raise TypeError('Argument is not an instance of Message') message.Message.attach(self, _msg) self.set_default_type('message/rfc822')
def _serialize_request(self, request): """Convert an HttpRequest object into a string. Args: request: HttpRequest, the request to serialize. Returns: The request as a string in application/http format. """ # Construct status line parsed = urlparse.urlparse(request.uri) request_line = urlparse.urlunparse( (None, None, parsed.path, parsed.params, parsed.query, None) ) status_line = request.method + ' ' + request_line + ' HTTP/1.1\n' major, minor = request.headers.get('content-type', 'application/json').split('/') msg = MIMENonMultipart(major, minor) headers = request.headers.copy() if request.http is not None and hasattr(request.http.request, 'credentials'): request.http.request.credentials.apply(headers) # MIMENonMultipart adds its own Content-Type header. if 'content-type' in headers: del headers['content-type'] for key, value in headers.iteritems(): msg[key] = value msg['Host'] = parsed.netloc msg.set_unixfrom(None) if request.body is not None: msg.set_payload(request.body) msg['content-length'] = str(len(request.body)) # Serialize the mime message. fp = StringIO.StringIO() # maxheaderlen=0 means don't line wrap headers. g = Generator(fp, maxheaderlen=0) g.flatten(msg, unixfrom=False) body = fp.getvalue() # Strip off the \n\n that the MIME lib tacks onto the end of the payload. if request.body is None: body = body[:-2] return status_line.encode('utf-8') + body
def __init__(self, _msg, _subtype='rfc822'): """Create a message/* type MIME document. _msg is a message object and must be an instance of Message, or a derived class of Message, otherwise a TypeError is raised. Optional _subtype defines the subtype of the contained message. The default is "rfc822" (this is defined by the MIME standard, even though the term "rfc822" is technically outdated by RFC 2822). """ MIMENonMultipart.__init__(self, 'message', _subtype) if not isinstance(_msg, message.Message): raise TypeError('Argument is not an instance of Message') # It's convenient to use this base class method. We need to do it # this way or we'll get an exception message.Message.attach(self, _msg) # And be sure our default type is set correctly self.set_default_type('message/rfc822')
def mbox(self): from email.mime.nonmultipart import MIMENonMultipart from email.encoders import encode_7or8bit body = '' if self.description: body += self.description.content + '\n' body += self.content mbox = MIMENonMultipart('text', 'plain', charset='utf-8') mbox['Subject'] = ": ".join([t.name for t in self.tags] + [self.name.strip().capitalize()]) mbox['From'] = '%s <%s>' % (self.submitter.name, self.submitter.email) mbox['Message-Id'] = self.msgid mbox.set_payload(body.encode('utf-8')) encode_7or8bit(mbox) return mbox.as_string()
def attachment_to_message(attachment): mtype, stype = attachment.content_type.split('/') if attachment.filename: msg = MIMENonMultipart(mtype, stype, name=attachment.filename) else: msg = MIMENonMultipart(mtype, stype) if attachment.disposition: if attachment.filename: msg.add_header('Content-Dispsition', attachment.disposition, filename=attachment.filename) else: msg.add_header('Content-Disposition', attachment.disposition) payload = attachment.data ctenc = attachment.transfer_encoding if ctenc: payload = encode_string(ctenc, payload) msg.add_header('Content-Transfer-Encoding', ctenc) msg.set_payload(payload, attachment.charset) return msg
def prepare_email_message(self): """ Returns a django ``EmailMessage`` or ``EmailMultiAlternatives`` object, depending on whether html_message is empty. """ if self.template is not None: engine = get_template_engine() subject = engine.from_string(self.template.subject).render(self.context) plaintext_message = engine.from_string(self.template.content).render(self.context) multipart_template = engine.from_string(self.template.html_content) html_message = multipart_template.render(self.context) else: subject = smart_text(self.subject) plaintext_message = self.message multipart_template = None html_message = self.html_message connection = connections[self.backend_alias or 'default'] if html_message: if plaintext_message: msg = EmailMultiAlternatives( subject=subject, body=plaintext_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=self.headers, connection=connection) msg.attach_alternative(html_message, "text/html") else: msg = EmailMultiAlternatives( subject=subject, body=html_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=self.headers, connection=connection) msg.content_subtype = 'html' if hasattr(multipart_template, 'attach_related'): multipart_template.attach_related(msg) else: msg = EmailMessage( subject=subject, body=plaintext_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=self.headers, connection=connection) for attachment in self.attachments.all(): if attachment.headers: mime_part = MIMENonMultipart(*attachment.mimetype.split('/')) mime_part.set_payload(attachment.file.read()) for key, val in attachment.headers.items(): try: mime_part.replace_header(key, val) except KeyError: mime_part.add_header(key, val) msg.attach(mime_part) else: msg.attach(attachment.name, attachment.file.read(), mimetype=attachment.mimetype or None) attachment.file.close() self._cached_email_message = msg return msg
def mbox(self): from email.mime.nonmultipart import MIMENonMultipart from email.encoders import encode_7or8bit body = '' if self.comments[0].msgid == self.msgid: body += self.comments[0].content + '\n' body += self.content mbox = MIMENonMultipart('text', 'plain', charset='utf-8') mbox['Subject'] = self.name mbox['From'] = '%s <%s>' % (self.submitter.name, self.submitter.email) mbox['Message-Id'] = self.msgid mbox.set_payload(body.encode('utf-8')) encode_7or8bit(mbox) return mbox.as_string()
def upload(self, filename): name = os.path.basename(filename) entry = self.get_info(name) if entry: self._delete(entry) #print "after check" size = os.path.getsize(filename) cype = guess_type(name) if not cype or not cype[0]: cype = "text/plain" else: cype = cype[0] url = "https://api.box.com/2.0/files/content" message = MIMEMultipart('mixed') # Message should not write out it's own headers. setattr(message, '_write_headers', lambda self: None) msg = MIMENonMultipart(*cype.split('/')) msg.add_header('Content-Disposition', 'form-data; name="f"; filename="%s"' % name) del msg["MIME-Version"] msg.set_payload(open(filename).read()) message.attach(msg) msg = MIMENonMultipart("text", "plain") msg.add_header('Content-Disposition', 'form-data; name="folder_id"') del msg["Content-Type"] del msg["MIME-Version"] msg.set_payload('0') message.attach(msg) body = message.as_string() #print body #return bd = message.get_boundary() hd = {"Content-Type": "multipart/form-data; boundary=%s" % bd} res = self.auth_http("POST", url, body, hd) ret = res.read() print(json.loads(ret)["entries"][0]['name'])
def patch_to_attachment(self, patch, index): # patches don't come with an encoding. If the patch is valid utf-8, # we'll attach it as MIMEText; otherwise, it gets attached as a binary # file. This will suit the vast majority of cases, since utf8 is by # far the most common encoding. if not isinstance(patch[1], types.UnicodeType): try: unicode = patch[1].decode('utf8') except UnicodeDecodeError: unicode = None else: unicode = patch[1] if unicode: a = MIMEText(unicode.encode(ENCODING), _charset=ENCODING) else: # MIMEApplication is not present in Python-2.4 :( a = MIMENonMultipart('application', 'octet-stream') a.set_payload(patch[1]) a.add_header('Content-Disposition', "attachment", filename="source patch " + str(index)) return a
def email_files(self): if os.getcwd() != self.filePathStorage: os.chdir(self.filePathStorage) try: # Changeable from the json object to_address = self.adr1 + ',' + self.adr2 + ',' + self.adr3 message = self.message subject = self.subject + " @" + str( self.current_date) # Added the date here since I needed it. files = [self.fileName1, self.fileName2, self.fileName3] server = smtplib.SMTP(str(self.host) + ":" + str(self.port)) server.starttls() server.login(self.host_usr, self.host_psw) # Setup the email header details msg = MIMEMultipart(From=self.host_usr, To=self.adr1 + ',' + self.adr2 + ',' + self.adr3, Date=formatdate(localtime=True), Subject=subject) # Setup backend email details msg['Subject'] = subject msg['To'] = self.adr1 + ',' + self.adr2 + ',' + self.adr3 msg.attach(MIMEText(message.replace('\\n', '\n'))) # Loop to attach all files in the files array for f in files: attachment = MIMENonMultipart('text', 'csv', charset='utf-8') attachment.set_payload(open(f, "rb").read()) encoders.encode_base64(attachment) attachment.add_header('Content-Disposition', 'attachment', filename=f) msg.attach(attachment) server.sendmail(self.host_usr, to_address, msg.as_string()) except smtplib.SMTPRecipientsRefused as e: print("Invalid address - {to_address}".format( to_address=self.adr1 + ',' + self.adr2 + ',' + self.adr3)) finally: print('Done') if server: server.quit()
def createMessage(self, recipients): msg = MIMEMultipart() msg['Subject'] = yamlLoad['SendInfo']['Subject'] msg['From'] = Sender msg['To'] = recipients if args.v: print( colored("Delivering to " + recipients + ", from: " + sender, "yellow")) data = MIMEText(yamlLoad['SendInfo']['Body'], 'html') msg.attach(data) if args.v: print(colored("Message to be delivered: \n", "yellow")) print(colored(data, "white", "on_blue")) if args.p: try: payloadPath = args.p fp = open(payloadPath, 'rb') attach = MIMENonMultipart('application', 'exe') payload = base64.b64encode(fp.read()).decode('ascii') attach.set_payload(payload) attach['Content-Transfer-Encoding'] = 'base64' nameFile = yamlLoad['SendInfo']['Attachment'] attach.add_header('Content-Disposition', 'attachment', filename=nameFile) msg.attach(attach) fp.close() if args.v: print( colored("Name of attachment to be sent: " + nameFile, "yellow")) except: print(colored("Incorrect file path \n", "yellow")) if args.v: print(colored("Message created successfuly \n", "green")) message = msg.as_string() return message
def get_content_block(self, f): binding_map = { '.xlsx': ('application', 'vnd.openxmlformats-officedocument.spreadsheetml.sheet'), '.xls': ('application', 'vnd.ms-excel'), '.csv': ('text', 'csv'), '.json': ('application', 'json'), '.syslog': ('text', 'syslog') } # Check the file extension to see if it is a supported type name_part, ext_part = os.path.splitext(f.name) if ext_part.lower() == '.xml': cb = tm11.ContentBlock(tm11.ContentBinding(t.CB_STIX_XML_101), f.read()) else: binding_tuple = binding_map.get(ext_part.lower(), None) if not binding_tuple: logger.error( 'File extension not supported: %s. Supported extensions: %s' % (ext_part, binding_map.keys())) return # Read the file and create a MIME message for it maintype = binding_tuple[0] subtype = binding_tuple[ 1] # Note: This is MIME subtype, not TAXII subtype mime_msg = MIMENonMultipart(maintype, subtype) mime_msg.add_header('Content-Disposition', 'attachment', filename=f.name) mime_msg.set_payload(f.read()) encode_base64(mime_msg) cb = tm11.ContentBlock('%s/%s' % (maintype, subtype), mime_msg.as_string()) return cb
def _serialize_request(self, request): """Convert an HttpRequest object into a string. Args: request: HttpRequest, the request to serialize. Returns: The request as a string in application/http format. """ # Construct status line parsed = urlparse.urlparse(request.uri) request_line = urlparse.urlunparse( (None, None, parsed.path, parsed.params, parsed.query, None) ) status_line = request.method + ' ' + request_line + ' HTTP/1.1\n' major, minor = request.headers.get('content-type', 'application/json').split('/') msg = MIMENonMultipart(major, minor) headers = request.headers.copy() # MIMENonMultipart adds its own Content-Type header. if 'content-type' in headers: del headers['content-type'] for key, value in headers.iteritems(): msg[key] = value msg['Host'] = parsed.netloc msg.set_unixfrom(None) if request.body is not None: msg.set_payload(request.body) msg['content-length'] = str(len(request.body)) body = msg.as_string(False) # Strip off the \n\n that the MIME lib tacks onto the end of the payload. if request.body is None: body = body[:-2] return status_line.encode('utf-8') + body
def get_mime(cls, report, record, language): pool = Pool() Report = pool.get(report.report_name, type='report') with Transaction().set_context(language=language): ext, content, _, title = Report.execute([record.id], { 'action_id': report.id, }) name = '%s.%s' % (title, ext) mimetype, _ = mimetypes.guess_type(name) if mimetype: msg = MIMENonMultipart(*mimetype.split('/')) msg.set_payload(content) encode_base64(msg) else: msg = MIMEApplication(content) if not isinstance(name, str): name = name.encode('utf-8') if not isinstance(language, str): language = language.encode('utf-8') msg.add_header('Content-Disposition', 'attachment', filename=('utf-8', language, name)) return msg
def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=None, sendername=None, receivername=None): # attachment format, each is a tuple of (name, mimetype,contents) # content should be *binary* and not base64 encoded, since we need to # use the base64 routines from the email library to get a properly # formatted output message msg = MIMEMultipart() msg['Subject'] = subject if receivername: msg['To'] = u'{0} <{1}>'.format(receivername, receiver) else: msg['To'] = receiver if sendername: msg['From'] = u'{0} <{1}>'.format(sendername, sender) else: msg['From'] = sender msg['Date'] = formatdate(localtime=True) msg.attach(MIMEText(msgtxt, _charset='utf-8')) if attachments: for filename, contenttype, content in attachments: main, sub = contenttype.split('/') part = MIMENonMultipart(main, sub) part.set_payload(content) part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename) encoders.encode_base64(part) msg.attach(part) # Just write it to the queue, so it will be transactionally rolled back QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string()).save() # Any bcc is just entered as a separate email if bcc: QueuedMail(sender=sender, receiver=bcc, fullmsg=msg.as_string()).save()
def _attachment_to_cdoc(self, content, content_type, encoder=encoders.encode_base64): major, sub = content_type.split('/') attachment = MIMENonMultipart(major, sub) attachment.set_payload(content) encoder(attachment) attachment.add_header('Content-Disposition', 'attachment', filename='does_not_matter.txt') pseudo_mail = MIMEMultipart() pseudo_mail.attach(attachment) tmp_mail = SoledadMailAdaptor().get_msg_from_string( MessageClass=Message, raw_msg=pseudo_mail.as_string()) cdoc = tmp_mail.get_wrapper().cdocs[1] return cdoc
async def _serialize_request(self, request): """ Convert an HttpRequest object into a string. Args: request: HttpRequest, the request to serialize. Returns: The request as a string in application/http format. """ parsed = urlparse(request.uri) request_line = urlunparse( ("", "", parsed.path, parsed.params, parsed.query, "")) status_line = request.method + " " + request_line + " HTTP/1.1\n" major, minor = request.headers.get("content-type", "application/json").split("/") msg = MIMENonMultipart(major, minor) headers = request.headers.copy() # MIMENonMultipart adds its own Content-Type header. if "content-type" in headers: del headers["content-type"] for key, value in headers.items(): msg[key] = value msg["Host"] = parsed.netloc msg.set_unixfrom(None) if request.body is not None: msg.set_payload(request.body) msg["content-length"] = str(len(request.body)) # Serialize the mime message. fp = StringIO() # maxheaderlen=0 means don't line wrap headers. g = Generator(fp, maxheaderlen=0) g.flatten(msg, unixfrom=False) body = fp.getvalue() return status_line + body
def sendPDF(fileName, email): smtp_ssl_host = 'smtp.gmail.com' smtp_ssl_port = 465 username = '******' password = '******' sender = '*****@*****.**' targets = [email] msg = MIMEMultipart() msg['Subject'] = 'Study Plan' msg['From'] = sender msg['To'] = ', '.join(targets) #Source for PDF send: https://bugs.python.org/issue9040 try: fp = open(fileName, 'rb') attach = MIMENonMultipart('application', 'pdf') payload = base64.b64encode(fp.read()).decode('ascii') attach.set_payload(payload) attach['Content-Transfer-Encoding'] = 'base64' fp.close() attach.add_header('Content-Disposition', 'attachment', filename='file.pdf') msg.attach(attach) #End of found fix server = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port) server.login(username, password) server.sendmail(sender, targets, msg.as_string()) server.quit() return "Sent study plan to: " + email except: print 'error/exception'
def craft_message(headers, body, attachments, embeddeds, mbx, is_html): """This function handles the creation of a Python email.message object from the headers and body lists created during the main loop.""" global edir attachments_ok = False embeddedcids = [] if body: msg_text = ''.join(body) else: msg_text = '' # there's no point honoring 'multipart' if we don't have any # attachments or embeddeds to attach, so we'll pay most # attention to whether we have any attachments or embeddeds # defined for this message if attachments or embeddeds: is_multipart = True else: is_multipart = False message = None contenttype = headers.getValue('Content-Type:') if contenttype and re_html.search(contenttype): is_html = True if not contenttype: msattach = headers.getValue('X-MS-Attachment:') if msattach: message = MIMEMultipart() attachments_ok = "Dunno" attachments_contenttype = "Still Dunno" else: if is_html: message = MIMENonMultipart('text', 'html') else: message = MIMENonMultipart('text', 'plain') attachments_ok = False attachments_contenttype = False print "T", elif re_rfc822.search(contenttype): print "[", message = MIMEMessage( craft_message(*extract_pieces(body, -1, mbx, True))) print "]", elif not is_multipart: mimetype = re_single_contenttype.search(contenttype) if mimetype: main = mimetype.group(1) sub = mimetype.group(2) if main != 'multipart': message = MIMENonMultipart(main, sub) attachments_ok = False attachments_contenttype = False print "X", else: # I've seen some messages in Eudora # mailboxes that label themselves as # multitype/related without having any # attachments ever declared in the # Eudora box. # # By passing here, we allow the next # clause to go ahead and create an # appropriate MIMENonMultipart pass if not message: if is_html: message = MIMENonMultipart('text', 'html') else: message = MIMENonMultipart('text', 'plain') attachments_ok = False attachments_contenttype = False else: subtype = re_multi_contenttype.search(contenttype) if subtype: message = MIMEMultipart(_subtype=subtype.group(1)) attachments_ok = subtype.group(1) attachments_contenttype = contenttype print "Y", else: message = MIMEMultipart() print "Z", attachments_ok = "Dunno" attachments_contenttype = "Still Dunno" # Need to add support here for processing embeddeds if embeddeds: if not isinstance(message, MIMEMultipart): print "\n\n==================================================\n" print "Found surprise multipart for embeddeds!\n" message = MIMEMultipart(_subtype='related') else: print "\n\n==================================================\n" print "Found embeddeds in multipart!\n" p = EudoraHTMLParser() try: p.feed(msg_text) cids = p.get_cids() except HTMLParseError: # okay, we've got unparseable HTML here. # Let's just use a quick regexp to see if we can make sense of this. cids = [] for match in re_cids_finder.finditer(msg_text): cids.append("cid:" + match.group(1)) if not len(cids) == len(embeddeds): print "cids / embeddeds mismatch!" print print mbx for piece in ['To:', 'From:', 'Subject:', 'Date:']: if headers.getValue(piece): print piece + " " + headers.getValue(piece)[:80] print print "\tcid\t\t\t\t\t\t\tembedded" i = 0 while i < len(cids) or i < len(embeddeds): if i < len(cids): print "%d.\t%s" % (i, cids[i]), print "\t" * (6 - (len(cids[i]) // 8)), else: print "%d.\t" % (i, ), print "\t\t\t\t\t\t", if i < len(embeddeds): print embeddeds[i], if edir and os.path.exists(edir + os.sep + embeddeds[i]): print " *" else: print " !" else: print i = i + 1 cidi = 0 embeddedi = 0 cidsmatched = set() while cidi < len(cids) or embeddedi < len(embeddeds): if cidi < len(cids) and embeddedi < len(embeddeds): if cids[cidi].startswith('cid:'): actualcid = cids[cidi][4:] else: actualcid = cids[cidi] # the document might have several img # references to the same cid.. we # don't want to try to mate up # multiple inline files in that case if actualcid in cidsmatched: cidi = cidi + 1 else: cidsmatched.add(actualcid) embeddedcids.append((actualcid, embeddeds[embeddedi])) embeddedi = embeddedi + 1 cidi = cidi + 1 elif embeddedi < len(embeddeds): embeddedcids.append((None, embeddeds[embeddedi])) embeddedi = embeddedi + 1 else: # we have more cids than # embeddeds, keep looping # through cidi = cidi + 1 print "\n\nAttaching inline components:" for c, f in embeddedcids: print "%s\t%s" % (c, f) print "\n==================================================\n" if attachments: if not isinstance(message, MIMEMultipart): #print "\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" #print "Forcing surprise multipart!\n" #print "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" message = MIMEMultipart() # bind the headers into our message set_headers(message, headers) try: # rfc822 MIMEMessage objects handle payload management # on constructions, we must not try to do it here. if not isinstance(message, MIMEMessage): if not isinstance(message, MIMEMultipart): message.set_payload(msg_text) elif is_html: message.attach(MIMEText(msg_text, _subtype='html')) else: message.attach(MIMEText(msg_text)) except Exception, e: print "\nHEY HEY HEY message = " + str(msg_text) + "\n" print "Type of message's payload is " + str(type( message.get_payload())) + "\n" if isinstance(message.get_payload(), list): print "Size of message's payload list is " + str( len(message.get_payload())) + "\n" print ")))))))))))))))))))) First part" print str(message.get_payload()[0]) print ">>>>>>>>>>>>>>>>>>>> Second part" print str(message.get_payload()[1]) print "attachments_contenttype is (%s)" % (attachments_contenttype, ) print "attachments_ok is (%s)" % (attachments_ok, ) if attachments: print "Yeah, attachments were found: %d" % (len(attachments), ) print "EXCEPTION " + str(e) + "\n" traceback.print_exc(file=sys.stdout)
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in six.iterkeys(kwargs): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) # Remove args that have a value of None. keys = list(kwargs.keys()) for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: # temporary workaround for non-paging methods incorrectly requiring # page token parameter (cf. drive.changes.watch vs. drive.changes.list) if name not in _PAGE_TOKEN_NAMES or _findPageTokenName( _methodProperties(methodDesc, schema, 'response')): raise TypeError('Missing required parameter "%s"' % name) for name, regex in six.iteritems(parameters.pattern_params): if name in kwargs: if isinstance(kwargs[name], six.string_types): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in six.iteritems(parameters.enum_params): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if (name in parameters.repeated_params and not isinstance(kwargs[name], six.string_types)): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, value, str(enums))) actual_query_params = {} actual_path_params = {} for key, value in six.iteritems(kwargs): to_type = parameters.param_types.get(key, 'string') # For repeated parameters we cast each member of the list. if key in parameters.repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) media_mime_type = kwargs.get('media_mime_type', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model if methodName.endswith('_media'): model = MediaModel() elif 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, six.string_types): if media_mime_type is None: logger.warning( 'media_mime_type argument not specified: trying to auto-detect for %s', media_filename) media_mime_type, _ = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if media_upload.size( ) is not None and media_upload.size() > maxSize > 0: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, 'uploadType', 'resumable') if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, 'uploadType', 'media') else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) # encode the body: note that we can't use `as_string`, because # it plays games with `From ` lines. fp = BytesIO() g = _BytesGenerator(fp, mangle_from_=False) g.flatten(msgRoot, unixfrom=False) body = fp.getvalue() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ( 'multipart/related; ' 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, 'uploadType', 'multipart') logger.info('URL being requested: %s %s' % (httpMethod, url)) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def build_email(mail_to, subject, body_text, mail_from='*****@*****.**', reply_to=None, attachments=None, mime_headers=None): """ Flexible Multipart MIME message builder. Implements message building using the "email" Python standard library https://docs.python.org/2/library/email-examples.html while following recommendations from https://stackoverflow.com/questions/3902455/smtp-multipart-alternative-vs-multipart-mixed .. seealso:: - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52243 - http://mail.python.org/pipermail/tutor/1999-June/000259.html - http://www.bigbold.com/snippets/posts/show/2038 """ attachments = attachments or {} mime_headers = mime_headers or {} # ------------------------------------------ # envelope # ------------------------------------------ message = MIMEMultipart('mixed') # TODO: Add text for non MIME-aware MUAs #message.preamble = 'You will not see this in a MIME-aware mail reader.\n' # Address headers address_headers = { 'To': fix_addresslist(AddressList(mail_to)), 'From': AddressList(mail_from), 'Reply-To': AddressList(reply_to), } # Subject header mime_headers.update({'Subject': Header(s=subject, charset='utf-8')}) # Add address headers for key, item in address_headers.items(): if isinstance(item, AddressList): # v1 #for address in format_addresslist(item): # message[key] = address # v2 value = ', '.join(format_addresslist(item)) if value: message[key] = value # Add more headers for key, value in mime_headers.items(): #message.add_header(key, value) if value: message[key] = value # ------------------------------------------ # email body # ------------------------------------------ body_message = MIMEMultipart('alternative') # Start off with a text/plain part # https://stackoverflow.com/questions/3902455/smtp-multipart-alternative-vs-multipart-mixed body_part1 = MIMEText(body_text, _subtype='plain', _charset='utf-8') #body_part1.set_payload(body_text) #body_part1.set_charset('utf-8') body_message.attach(body_part1) message.attach(body_message) # TODO: Add a text/html part #body_part2 = MIMEText(body_html, 'html') # ------------------------------------------ # multipart attachments # ------------------------------------------ # from https://docs.python.org/2/library/email-examples.html for filename, payload in attachments.items(): # 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(filename, strict=False) #print('ctype, encoding:', ctype, encoding) if ctype is None or encoding is not None: # No guess could be made, or the file is encoded (compressed), so # use a generic bag-of-bits type. ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) #print('maintype, subtype:', maintype, subtype) # Create proper MIME part by maintype if maintype == 'application' and subtype in ['xml', 'json']: part = MIMENonMultipart(maintype, subtype, charset='utf-8') part.set_payload(payload.encode('utf-8'), 'utf-8') elif maintype == 'text': part = MIMEText(payload.encode('utf-8'), _subtype=subtype, _charset='utf-8') #part.set_charset('utf-8') elif maintype == 'image': part = MIMEImage(payload, _subtype=subtype) elif maintype == 'audio': part = MIMEAudio(payload, _subtype=subtype) else: part = MIMEBase(maintype, subtype) part.set_payload(payload) # Encode the payload using Base64 (Content-Transfer-Encoding) encoders.encode_base64(part) #part = MIMEBase(maintype, subtype, _charset='utf-8') # replace forward slashes by dashes filename_attachment = filename.lstrip('/\\').replace('/', '-') part.add_header('Content-Disposition', 'attachment', filename=filename_attachment.encode('utf-8')) #part.set_payload(payload.encode('utf-8')) #part.set_charset('utf-8') # Encode the payload using Base64 (Content-Transfer-Encoding) #encoders.encode_base64(part) # Add part to multipart message message.attach(part) payload = message.as_string() return payload
def send(cls, to='', cc='', bcc='', subject='', body='', files=None, record=None, reports=None, attachments=None): pool = Pool() User = pool.get('res.user') ActionReport = pool.get('ir.action.report') Attachment = pool.get('ir.attachment') transaction = Transaction() user = User(transaction.user) Model = pool.get(record[0]) record = Model(record[1]) body_html = HTML_EMAIL % { 'subject': subject, 'body': body, 'signature': user.signature or '', } content = MIMEMultipart('alternative') if html2text: body_text = HTML_EMAIL % { 'subject': subject, 'body': body, 'signature': '', } converter = html2text.HTML2Text() body_text = converter.handle(body_text) if user.signature: body_text += '\n-- \n' + converter.handle(user.signature) part = MIMEText(body_text, 'plain', _charset='utf-8') content.attach(part) part = MIMEText(body_html, 'html', _charset='utf-8') content.attach(part) if files or reports or attachments: msg = MIMEMultipart('mixed') msg.attach(content) if files is None: files = [] else: files = list(files) for report_id in (reports or []): report = ActionReport(report_id) Report = pool.get(report.report_name, type='report') ext, content, _, title = Report.execute([record.id], { 'action_id': report.id, }) name = '%s.%s' % (title, ext) if isinstance(content, str): content = content.encode('utf-8') files.append((name, content)) if attachments: files += [(a.name, a.data) for a in Attachment.browse(attachments)] for name, data in files: mimetype, _ = mimetypes.guess_type(name) if mimetype: attachment = MIMENonMultipart(*mimetype.split('/')) attachment.set_payload(data) encode_base64(attachment) else: attachment = MIMEApplication(data) attachment.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', name)) msg.attach(attachment) else: msg = content from_ = config.get('email', 'from') set_from_header(msg, from_, user.email or from_) msg['To'] = ', '.join(formataddr(a) for a in getaddresses([to])) msg['Cc'] = ', '.join(formataddr(a) for a in getaddresses([cc])) msg['Subject'] = Header(subject, 'utf-8') to_addrs = list( filter( None, map(str.strip, _get_emails(to) + _get_emails(cc) + _get_emails(bcc)))) sendmail_transactional(from_, to_addrs, msg, datamanager=SMTPDataManager(strict=True)) email = cls(recipients=to, recipients_secondary=cc, recipients_hidden=bcc, addresses=[{ 'address': a } for a in to_addrs], subject=subject, body=body, resource=record) email.save() with Transaction().set_context(_check_access=False): attachments_ = [] for name, data in files: attachments_.append( Attachment(resource=email, name=name, data=data)) Attachment.save(attachments_) return email
def to_message(base): """ Given a MailBase, this will construct a MIME part that is canonicalized for use with the Python email API. """ ctype, ctparams = base.get_content_type() if not ctype: if base.parts: ctype = 'multipart/mixed' else: ctype = 'text/plain' maintype, subtype = ctype.split('/') is_text = maintype == 'text' is_multipart = maintype == 'multipart' if base.parts and not is_multipart: raise RuntimeError( 'Content type should be multipart, not %r' % ctype ) body = base.get_body() ctenc = base.get_transfer_encoding() charset = ctparams.get('charset') if is_multipart: out = MIMEMultipart(subtype, **ctparams) else: out = MIMENonMultipart(maintype, subtype, **ctparams) if ctenc: out['Content-Transfer-Encoding'] = ctenc if isinstance(body, text_type): if not charset: if is_text: charset, _ = best_charset(body) else: charset = 'utf-8' if PY2: body = body.encode(charset) else: body = body.encode(charset, 'surrogateescape') if body is not None: if ctenc: body = transfer_encode(ctenc, body) if not PY2: body = body.decode(charset or 'ascii', 'replace') out.set_payload(body, charset) for k in base.keys(): # returned sorted value = base[k] if not value: continue out[k] = value cdisp, cdisp_params = base.get_content_disposition() if cdisp: out.add_header('Content-Disposition', cdisp, **cdisp_params) # go through the children for part in base.parts: sub = to_message(part) out.attach(sub) return out
def mock_send_request(path, method, body, content_type): self.assertEqual('POST', method) self.assertEqual('https://www.googleapis.com/batch', path) match = re.match('multipart/mixed; boundary="([^\"]+)"', content_type) self.assertTrue(match) parts = body.split('--{0}'.format(match.group(1))) self.assertEqual(gce_base.MAX_BATCH_SIZE + 2, len(parts)) self.assertEqual('', parts[0]) self.assertEqual('--', parts[-1]) parts = parts[1:-1] responses = [] for part in parts: headers, payload = part.split('\n\n', 1) headers = parse_headers(headers) self.assertEqual('application/http', headers['Content-Type']) content_id = headers['Content-ID'] self.assertTrue( content_id.startswith('<') and content_id.endswith('>')) content_id = content_id[1:-1] http_headers = payload.split('\n\n', 1)[0] split = http_headers.split( '\n', 1) # Try to split off the http command http_request = split[0] if len(split) > 1: headers = parse_headers(split[1]) verb, path = http_request.split(' ') self.assertEqual('GET', verb) name = re.match('.*/([^/]+)', path).group(1) payload = '{{ "kind": "compute#instance", "name": "{0}" }}'.format( name) msg = MIMENonMultipart('application', 'http') msg.add_header('Content-ID', '<response-{0}>'.format(content_id)) msg.set_payload( 'HTTP/1.1 200 OK\n' 'Content-Type: application/json; charset=UTF-8\n' 'Content-Length: {0}\n\n' '{1}'.format(len(payload), payload)) responses.append(msg) random.shuffle(responses) response = gce_base._BatchApiRequest() for r in responses: response.attach(r) response_string = response.as_string() boundary = response.get_boundary() response = httplib2.Response({ 'content-type': 'multipart/mixed; boundary="{0}"'.format(boundary), 'status': 200, 'reason': 'OK' }) return response, response_string
def _process_msg(self, base_msg, append_msg): def find_ctype(payload): return handlers.type_from_starts_with(payload) for part in base_msg.walk(): if is_skippable(part): continue ctype = None ctype_orig = part.get_content_type() payload = util.fully_decoded_payload(part) was_compressed = False # When the message states it is of a gzipped content type ensure # that we attempt to decode said payload so that the decompressed # data can be examined (instead of the compressed data). if ctype_orig in DECOMP_TYPES: try: payload = util.decomp_gzip(payload, quiet=False) # At this point we don't know what the content-type is # since we just decompressed it. ctype_orig = None was_compressed = True except util.DecompressionError as e: LOG.warning( "Failed decompressing payload from %s of" " length %s due to: %s", ctype_orig, len(payload), e) continue # Attempt to figure out the payloads content-type if not ctype_orig: ctype_orig = UNDEF_TYPE if ctype_orig in TYPE_NEEDED: ctype = find_ctype(payload) if ctype is None: ctype = ctype_orig # In the case where the data was compressed, we want to make sure # that we create a new message that contains the found content # type with the uncompressed content since later traversals of the # messages will expect a part not compressed. if was_compressed: maintype, subtype = ctype.split("/", 1) n_part = MIMENonMultipart(maintype, subtype) n_part.set_payload(payload) # Copy various headers from the old part to the new one, # but don't include all the headers since some are not useful # after decoding and decompression. if part.get_filename(): _set_filename(n_part, part.get_filename()) for h in ('Launch-Index', ): if h in part: _replace_header(n_part, h, str(part[h])) part = n_part if ctype != ctype_orig: _replace_header(part, CONTENT_TYPE, ctype) if ctype in INCLUDE_TYPES: self._do_include(payload, append_msg) continue if ctype in ARCHIVE_TYPES: self._explode_archive(payload, append_msg) continue # TODO(harlowja): Should this be happening, shouldn't # the part header be modified and not the base? _replace_header(base_msg, CONTENT_TYPE, ctype) self._attach_part(append_msg, part)
async def execute(self, access_token=None): if access_token is None: if self.access_token is None: raise ValueError("Access token is not specified") access_token = self.access_token else: self.access_token = access_token """Validated credentials before calling this coroutine.""" message = MIMEMultipart("mixed") # Message should not write out it's own headers. setattr(message, "_write_headers", lambda arg: None) for rid, request in enumerate(self.requests): msg_part = MIMENonMultipart("application", "http") msg_part["Content-Transfer-Encoding"] = "binary" msg_part["Content-ID"] = self._id_to_header(str(rid)) body = await asyncio.create_task(self._serialize_request(request)) msg_part.set_payload(body) message.attach(msg_part) fp = StringIO() g = Generator(fp, mangle_from_=False) g.flatten(message, unixfrom=False) body = fp.getvalue() headers = {} headers[ "content-type"] = f'multipart/mixed; boundary="{message.get_boundary()}"' headers['authorization'] = access_token LOG.debug("Sending the batch request...") p1 = time.perf_counter() backoff = 1 while True: try: async with aiohttp.ClientSession() as session: async with session.post(url=self._batch_uri, data=body, headers=headers) as response: status = response.status if 200 <= status < 300: content = await response.text(encoding='utf-8') elif status == 403 or status == 429: LOG.warning( f"Rate limit exceeded while sending the batch request" f"(403={status==403,}, 429={status==429}), waiting {backoff} seconds." ) await asyncio.sleep(backoff) backoff *= 2 if backoff > 32: data = await response.text(encoding='utf-8') LOG.error( f"Repeated rate limit errors. Last error: {data}" ) raise BatchError(f"{data}") elif status == 401: LOG.warning( "BatchApiRequest.execute: 401 error encountered. Refreshing the token..." ) headers[ 'authorization'] = await asyncio.create_task( get_cached_token(GMAIL_TOKEN_ID)) else: data = await response.text(encoding='utf-8') LOG.error( f"Unhandled error in BatchApiRequest.execute. Error: {data}" ) raise BatchError(f"{data}") p2 = time.perf_counter() LOG.info(f"Batch response fetched in : {p2 - p1} seconds.") except aiohttp.ClientConnectionError as err: if backoff > 32: LOG.error( "Failed to send the batch request. Batch endpoint is unreachable and " "back-off is greater than 32 seconds.") raise LOG.warning( f"Batch endpoint is unreachable, waiting {backoff} seconds." ) await asyncio.sleep(backoff) backoff *= 2 else: break await self.handle_response(response, content) if len(self.requests) > 0: LOG.warning( f"{len(self.requests)} tasks FAILED, calling execute again.") await self.execute() return self.completed_responses
def method(self, **kwargs): for name in kwargs.iterkeys(): if name not in argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) for name in required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in pattern_params.iteritems(): if name in kwargs: if isinstance(kwargs[name], basestring): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in enum_params.iteritems(): if name in kwargs: if kwargs[name] not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, kwargs[name], str(enums))) actual_query_params = {} actual_path_params = {} for key, value in kwargs.iteritems(): to_type = param_type.get(key, 'string') # For repeated parameters we cast each member of the list. if key in repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in query_params: actual_query_params[argmap[key]] = cast_value if key in path_params: actual_path_params[argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey headers = {} headers, params, query, body = self._model.request( headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Convert a simple filename into a MediaUpload object. if isinstance(media_filename, basestring): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError( 'media_filename must be str or MediaUpload. Got %s' % type(media_upload)) if media_upload.resumable(): resumable = media_upload # Check the maxSize if maxSize > 0 and media_upload.size() > maxSize: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads if media_upload.resumable(): expanded_url = uritemplate.expand(mediaResumablePathUrl, params) else: expanded_url = uritemplate.expand(mediaPathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() expanded_url = uritemplate.expand(mediaResumablePathUrl, params) if not media_upload.resumable(): body = media_upload.getbytes(0, media_upload.size()) else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' if media_upload.resumable(): # This is a multipart resumable upload, where a multipart payload # looks like this: # # --===============1678050750164843052== # Content-Type: application/json # MIME-Version: 1.0 # # {'foo': 'bar'} # --===============1678050750164843052== # Content-Type: image/png # MIME-Version: 1.0 # Content-Transfer-Encoding: binary # # <BINARY STUFF> # --===============1678050750164843052==-- # # In the case of resumable multipart media uploads, the <BINARY # STUFF> is large and will be spread across multiple PUTs. What we # do here is compose the multipart message with a random payload in # place of <BINARY STUFF> and then split the resulting content into # two pieces, text before <BINARY STUFF> and text after <BINARY # STUFF>. The text after <BINARY STUFF> is the multipart boundary. # In apiclient.http the HttpRequest will send the text before # <BINARY STUFF>, then send the actual binary media in chunks, and # then will send the multipart delimeter. payload = hex(random.getrandbits(300)) msg.set_payload(payload) msgRoot.attach(msg) body = msgRoot.as_string() body, _ = body.split(payload) resumable = media_upload else: payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) body = msgRoot.as_string() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ( 'multipart/related; ' 'boundary="%s"') % multipart_boundary logging.info('URL being requested: %s' % url) return self._requestBuilder(self._http, self._model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def execute(self, http=None): """Execute all the requests as a single batched HTTP request. Args: http: httplib2.Http, an http object to be used in place of the one the HttpRequest request object was constructed with. If one isn't supplied then use a http object from the requests in this batch. Returns: None Raises: apiclient.errors.HttpError if the response was not a 2xx. httplib2.Error if a transport error has occured. """ if http is None: for request_id in self._order: request, callback = self._requests[request_id] if request is not None: http = request.http break if http is None: raise ValueError("Missing a valid http object.") msgRoot = MIMEMultipart('mixed') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # Add all the individual requests. for request_id in self._order: request, callback = self._requests[request_id] msg = MIMENonMultipart('application', 'http') msg['Content-Transfer-Encoding'] = 'binary' msg['Content-ID'] = self._id_to_header(request_id) body = self._serialize_request(request) msg.set_payload(body) msgRoot.attach(msg) body = msgRoot.as_string() headers = {} headers['content-type'] = ('multipart/mixed; ' 'boundary="%s"') % msgRoot.get_boundary() resp, content = http.request(self._batch_uri, 'POST', body=body, headers=headers) if resp.status >= 300: raise HttpError(resp, content, self._batch_uri) # Now break up the response and process each one with the correct postproc # and trigger the right callbacks. boundary, _ = content.split(None, 1) # Prepend with a content-type header so FeedParser can handle it. header = 'Content-Type: %s\r\n\r\n' % resp['content-type'] content = header + content parser = FeedParser() parser.feed(content) respRoot = parser.close() if not respRoot.is_multipart(): raise BatchError("Response not in multipart/mixed format.") parts = respRoot.get_payload() for part in parts: request_id = self._header_to_id(part['Content-ID']) headers, content = self._deserialize_response(part.get_payload()) # TODO(jcgregorio) Remove this temporary hack once the server stops # gzipping individual response bodies. if content[0] != '{': gzipped_content = content content = gzip.GzipFile( fileobj=StringIO.StringIO(gzipped_content)).read() request, cb = self._requests[request_id] postproc = request.postproc response = postproc(resp, content) if cb is not None: cb(request_id, response) if self._callback is not None: self._callback(request_id, response)
def _send_batch_request(self, requests): """Sends a batch of requests to the server and processes the HTTP responses. Args: requests: List of GoogleComputeEngineBase.API_REQUEST named tuples. Must contain <= MAX_BATCH_SIZE elements. Raises: ValueError: If requests has more than MAX_BATCH_SIZE elements. Returns: List of GoogleComputeEngineBase.BATCH_RESPONSE named tuples, one for each element of request parameter. """ if len(requests) > MAX_BATCH_SIZE: raise ValueError('Too many requests provided' '(maximum is {0})'.format(MAX_BATCH_SIZE)) batch = _BatchApiRequest() base = urlparse.urlsplit(self.base_url) base_path = base.path.rstrip('/') for i, request in enumerate(requests): msg = MIMENonMultipart('application', 'http') msg.add_header('Content-ID', '<{0}>'.format(i)) msg.set_payload( self._serialize_batch_api_request(base_path, request)) batch.attach(msg) batch_string = batch.as_string() content_type = 'multipart/mixed; boundary="{0}"'.format( batch.get_boundary()) url = urlparse.urlunsplit((base.scheme, base.netloc, 'batch', self._create_url_query(None), None)) response, data = self._send_request(url, 'POST', batch_string, content_type) if response.status >= 300: error = gce.GceError(message=response.reason, status=response.status) return [error] * len(requests) # Return all errors. elif not data: error = gce.GceError(message='Server returned no data', status=response.status) return [error] * len(requests) # Return all errors. # Process successful response. data = 'content-type: {0}\r\n\r\n'.format( response['content-type']) + data parser = FeedParser() parser.feed(data) response = parser.close() responses = [] for part in response.get_payload(): responses.append( (int(RESPONSE_ID_REGEX.match(part['Content-ID']).group(1)), self._parse_batch_api_response(part.get_payload()))) responses.sort(key=lambda r: r[0]) return [r[1] for r in responses]
NEW_PURPOSE_REGISTER: { 'subject': _('Your new account on %(domain)s'), }, NEW_PURPOSE_SET_PASSWORD: { 'subject': _('Reset the password for your %(domain)s account'), }, NEW_PURPOSE_SET_EMAIL: { 'subject': _l('Confirm the email address for your %(domain)s account'), }, NEW_PURPOSE_DELETE: { 'subject': _l('Delete your account on %(domain)s'), }, } log = logging.getLogger(__name__) pgp_version = MIMENonMultipart('application', 'pgp-encrypted') pgp_version.add_header('Content-Description', 'PGP/MIME version identification') pgp_version.set_payload('Version: 1\n') @python_2_unicode_compatible class RegistrationUser(XmppBackendUser): # NOTE: MySQL only allows a 255 character limit jid = models.CharField(max_length=255, unique=True, verbose_name='JID') email = models.EmailField(null=True, blank=True) gpg_fingerprint = models.CharField(max_length=40, null=True, blank=True) # when the account was first registered registered = models.DateTimeField(auto_now_add=True) registration_method = models.SmallIntegerField(
def as_message(self, escape_addresses=True): # http://wordeology.com/computer/how-to-send-good-unicode-email-with-python.html # http://stackoverflow.com/questions/31714221/how-to-send-an-email-with-quoted # http://stackoverflow.com/questions/9403265/how-do-i-use-python/9509718#9509718 charset = Charset('utf-8') charset.header_encoding = QP charset.body_encoding = QP msg = MIMEMultipart() # Headers unixfrom = "From %s %s" % (self.sender.address, self.archived_date.strftime("%c")) header_from = self.sender.address if self.sender_name and self.sender_name != self.sender.address: header_from = "%s <%s>" % (self.sender_name, header_from) header_to = self.mailinglist.name if escape_addresses: header_from = header_from.replace("@", " at ") header_to = header_to.replace("@", " at ") unixfrom = unixfrom.replace("@", " at ") msg.set_unixfrom(unixfrom) headers = ( ("From", header_from), ("To", header_to), ("Subject", self.subject), ) for header_name, header_value in headers: if not header_value: continue try: msg[header_name] = header_value.encode('ascii') except UnicodeEncodeError: msg[header_name] = Header(header_value.encode('utf-8'), charset).encode() tz = get_fixed_timezone(self.timezone) header_date = self.date.astimezone(tz).replace(microsecond=0) # Date format: http://tools.ietf.org/html/rfc5322#section-3.3 msg["Date"] = header_date.strftime("%a, %d %b %Y %H:%M:%S %z") msg["Message-ID"] = "<%s>" % self.message_id if self.in_reply_to: msg["In-Reply-To"] = self.in_reply_to # Body content = self.ADDRESS_REPLACE_RE.sub(r"\1(a)\2", self.content) # Don't use MIMEText, it won't encode to quoted-printable textpart = MIMENonMultipart("text", "plain", charset='utf-8') textpart.set_payload(content, charset=charset) msg.attach(textpart) # Attachments for attachment in self.attachments.order_by("counter"): mimetype = attachment.content_type.split('/', 1) part = MIMEBase(mimetype[0], mimetype[1]) part.set_payload(attachment.content) encode_base64(part) part.add_header('Content-Disposition', 'attachment', filename=attachment.name) msg.attach(part) return msg
def prepare_email_message(self): """ Returns a django ``EmailMessage`` or ``EmailMultiAlternatives`` object, depending on whether html_message is empty. """ if get_override_recipients(): self.to = get_override_recipients() if self.template is not None: engine = get_template_engine() subject = engine.from_string(self.template.subject).render( self.context) plaintext_message = engine.from_string( self.template.content).render(self.context) multipart_template = engine.from_string(self.template.html_content) html_message = multipart_template.render(self.context) else: subject = smart_str(self.subject) plaintext_message = self.message multipart_template = None html_message = self.html_message connection = connections[self.backend_alias or 'default'] if isinstance(self.headers, dict) or self.expires_at: headers = dict(self.headers or {}) if self.expires_at: headers.update({ 'Expires': self.expires_at.strftime("%a, %-d %b %H:%M:%S %z") }) else: headers = None if html_message: if plaintext_message: msg = EmailMultiAlternatives(subject=subject, body=plaintext_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=headers, connection=connection) msg.attach_alternative(html_message, "text/html") else: msg = EmailMultiAlternatives(subject=subject, body=html_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=headers, connection=connection) msg.content_subtype = 'html' if hasattr(multipart_template, 'attach_related'): multipart_template.attach_related(msg) else: msg = EmailMessage(subject=subject, body=plaintext_message, from_email=self.from_email, to=self.to, bcc=self.bcc, cc=self.cc, headers=headers, connection=connection) for attachment in self.attachments.all(): if attachment.headers: mime_part = MIMENonMultipart(*attachment.mimetype.split('/')) mime_part.set_payload(attachment.file.read()) for key, val in attachment.headers.items(): try: mime_part.replace_header(key, val) except KeyError: mime_part.add_header(key, val) msg.attach(mime_part) else: msg.attach(attachment.name, attachment.file.read(), mimetype=attachment.mimetype or None) attachment.file.close() self._cached_email_message = msg return msg
def __init__(self, _text): MIMENonMultipart.__init__(self, 'text', 'plain', **{'charset': self.patch_charset}) self.set_payload(_text.encode(self.patch_charset)) encode_7or8bit(self)
def method(self, **kwargs): for name in six.iterkeys(kwargs): if name not in argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) for name in required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in six.iteritems(pattern_params): if name in kwargs: if isinstance(kwargs[name], six.string_types): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in six.iteritems(enum_params): if name in kwargs: if kwargs[name] not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, kwargs[name], str(enums))) actual_query_params = {} actual_path_params = {} for key, value in six.iteritems(kwargs): to_type = param_type.get(key, 'string') # For repeated parameters we cast each member of the list. if key in repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in query_params: actual_query_params[argmap[key]] = cast_value if key in path_params: actual_path_params[argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model # If there is no schema for the response then presume a binary blob. if 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = six.moves.urllib.parse.urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, six.string_types): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if maxSize > 0 and media_upload.size() > maxSize: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads if media_upload.resumable(): expanded_url = uritemplate.expand(mediaResumablePathUrl, params) else: expanded_url = uritemplate.expand(mediaPathUrl, params) url = six.moves.urllib.parse.urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) body = msgRoot.as_string() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ('multipart/related; ' 'boundary="%s"') % multipart_boundary logging.info('URL being requested: %s' % url) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def send_email(smtp, recipients, cc, subject, content, csv_reports): """Sends an email with attachment. Refer to https://gist.github.com/BietteMaxime/f75ae41f7b4557274a9f Args: smtp: A dictionary containing smtp info: - smtp_url - smtp_auth_username # optional - smtp_auth_password # optional - smtp_from recipients: To whom to send the email. cc: To whom to cc the email. subject: Email subject. content: Email body content csv_reports: List of dictionaries containing "filename", "data" to construct CSV attachments. Returns: None """ if not isinstance(smtp, dict): logger.warning("smtp is not a dictionary. Skip.") return sender = smtp.get("smtp_from", None) smtp_url = smtp.get("smtp_url", None) smtp_auth_username = smtp.get("smtp_auth_username", None) smtp_auth_password = smtp.get("smtp_auth_password", None) if sender is None or smtp_url is None: logger.warning("Some fields in smtp %s is None. Skip.", smtp) return # Create message container - the correct MIME type is multipart/mixed # to allow attachment. full_email = MIMEMultipart("mixed") full_email["Subject"] = subject full_email["From"] = sender full_email["To"] = ", ".join(recipients) full_email["CC"] = ", ".join(cc) # Create the body of the message (a plain-text version). content = content.encode(ENCODING) content = MIMEText(content, "plain", _charset=ENCODING) full_email.attach(content) # Create the attachment of the message in text/csv. for report in csv_reports: attachment = MIMENonMultipart("text", "csv", charset=ENCODING) attachment.add_header("Content-Disposition", "attachment", filename=report["filename"]) cs = Charset(ENCODING) cs.body_encoding = BASE64 attachment.set_payload(report["data"].encode(ENCODING), charset=cs) full_email.attach(attachment) try: with smtplib.SMTP(smtp_url) as server: if smtp_auth_username is not None and smtp_auth_password is not None: server.starttls() server.login(smtp_auth_username, smtp_auth_password) receivers = recipients + cc server.sendmail(sender, receivers, full_email.as_string()) logger.info("Successfully sent email to %s and cc %s", ", ".join(recipients), ", ".join(cc)) except smtplib.SMTPAuthenticationError: logger.warning("The server didn\'t accept the user\\password " "combination.") except smtplib.SMTPServerDisconnected: logger.warning("Server unexpectedly disconnected") except smtplib.SMTPException as e: logger.exception("SMTP error occurred: %s", e)
def method(self, **kwargs): for name in kwargs.iterkeys(): if name not in argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) for name in required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in pattern_params.iteritems(): if name in kwargs: if re.match(regex, kwargs[name]) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, kwargs[name], regex)) for name, enums in enum_params.iteritems(): if name in kwargs: if kwargs[name] not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, kwargs[name], str(enums))) actual_query_params = {} actual_path_params = {} for key, value in kwargs.iteritems(): to_type = param_type.get(key, 'string') # For repeated parameters we cast each member of the list. if key in repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in query_params: actual_query_params[argmap[key]] = cast_value if key in path_params: actual_path_params[argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey headers = {} headers, params, query, body = self._model.request( headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) if media_filename: (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) # Check the maxSize if maxSize > 0 and os.path.getsize(media_filename) > maxSize: raise MediaUploadSizeError(media_filename) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) if body is None: headers['content-type'] = media_mime_type # make the body the contents of the file f = file(media_filename, 'rb') body = f.read() f.close() else: msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_mime_type.split('/')) msg['Content-Transfer-Encoding'] = 'binary' f = file(media_filename, 'rb') msg.set_payload(f.read()) f.close() msgRoot.attach(msg) body = msgRoot.as_string() # must appear after the call to as_string() to get the right boundary headers['content-type'] = ( 'multipart/related; ' 'boundary="%s"') % msgRoot.get_boundary() logging.info('URL being requested: %s' % url) return self._requestBuilder(self._http, self._model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId)