Index: tools/telemetry/third_party/gsutil/third_party/boto/boto/ses/connection.py |
diff --git a/tools/telemetry/third_party/gsutil/third_party/boto/boto/ses/connection.py b/tools/telemetry/third_party/gsutil/third_party/boto/boto/ses/connection.py |
deleted file mode 100644 |
index 244029a07ad1fc13da65b4bbba9def6dd08f54da..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/third_party/gsutil/third_party/boto/boto/ses/connection.py |
+++ /dev/null |
@@ -1,565 +0,0 @@ |
-# Copyright (c) 2010 Mitch Garnaat http://garnaat.org/ |
-# Copyright (c) 2011 Harry Marr http://hmarr.com/ |
-# |
-# Permission is hereby granted, free of charge, to any person obtaining a |
-# copy of this software and associated documentation files (the |
-# "Software"), to deal in the Software without restriction, including |
-# without limitation the rights to use, copy, modify, merge, publish, dis- |
-# tribute, sublicense, and/or sell copies of the Software, and to permit |
-# persons to whom the Software is furnished to do so, subject to the fol- |
-# lowing conditions: |
-# |
-# The above copyright notice and this permission notice shall be included |
-# in all copies or substantial portions of the Software. |
-# |
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
-# IN THE SOFTWARE. |
-import re |
-import base64 |
- |
-from boto.compat import six, urllib |
-from boto.connection import AWSAuthConnection |
-from boto.exception import BotoServerError |
-from boto.regioninfo import RegionInfo |
-import boto |
-import boto.jsonresponse |
-from boto.ses import exceptions as ses_exceptions |
- |
- |
-class SESConnection(AWSAuthConnection): |
- |
- ResponseError = BotoServerError |
- DefaultRegionName = 'us-east-1' |
- DefaultRegionEndpoint = 'email.us-east-1.amazonaws.com' |
- APIVersion = '2010-12-01' |
- |
- def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, |
- is_secure=True, port=None, proxy=None, proxy_port=None, |
- proxy_user=None, proxy_pass=None, debug=0, |
- https_connection_factory=None, region=None, path='/', |
- security_token=None, validate_certs=True, profile_name=None): |
- if not region: |
- region = RegionInfo(self, self.DefaultRegionName, |
- self.DefaultRegionEndpoint) |
- self.region = region |
- super(SESConnection, self).__init__(self.region.endpoint, |
- aws_access_key_id, aws_secret_access_key, |
- is_secure, port, proxy, proxy_port, |
- proxy_user, proxy_pass, debug, |
- https_connection_factory, path, |
- security_token=security_token, |
- validate_certs=validate_certs, |
- profile_name=profile_name) |
- |
- def _required_auth_capability(self): |
- return ['ses'] |
- |
- def _build_list_params(self, params, items, label): |
- """Add an AWS API-compatible parameter list to a dictionary. |
- |
- :type params: dict |
- :param params: The parameter dictionary |
- |
- :type items: list |
- :param items: Items to be included in the list |
- |
- :type label: string |
- :param label: The parameter list's name |
- """ |
- if isinstance(items, six.string_types): |
- items = [items] |
- for i in range(1, len(items) + 1): |
- params['%s.%d' % (label, i)] = items[i - 1] |
- |
- def _make_request(self, action, params=None): |
- """Make a call to the SES API. |
- |
- :type action: string |
- :param action: The API method to use (e.g. SendRawEmail) |
- |
- :type params: dict |
- :param params: Parameters that will be sent as POST data with the API |
- call. |
- """ |
- ct = 'application/x-www-form-urlencoded; charset=UTF-8' |
- headers = {'Content-Type': ct} |
- params = params or {} |
- params['Action'] = action |
- |
- for k, v in params.items(): |
- if isinstance(v, six.text_type): # UTF-8 encode only if it's Unicode |
- params[k] = v.encode('utf-8') |
- |
- response = super(SESConnection, self).make_request( |
- 'POST', |
- '/', |
- headers=headers, |
- data=urllib.parse.urlencode(params) |
- ) |
- body = response.read().decode('utf-8') |
- if response.status == 200: |
- list_markers = ('VerifiedEmailAddresses', 'Identities', |
- 'DkimTokens', 'DkimAttributes', |
- 'VerificationAttributes', 'SendDataPoints') |
- item_markers = ('member', 'item', 'entry') |
- |
- e = boto.jsonresponse.Element(list_marker=list_markers, |
- item_marker=item_markers) |
- h = boto.jsonresponse.XmlHandler(e, None) |
- h.parse(body) |
- return e |
- else: |
- # HTTP codes other than 200 are considered errors. Go through |
- # some error handling to determine which exception gets raised, |
- self._handle_error(response, body) |
- |
- def _handle_error(self, response, body): |
- """ |
- Handle raising the correct exception, depending on the error. Many |
- errors share the same HTTP response code, meaning we have to get really |
- kludgey and do string searches to figure out what went wrong. |
- """ |
- boto.log.error('%s %s' % (response.status, response.reason)) |
- boto.log.error('%s' % body) |
- |
- if "Address blacklisted." in body: |
- # Delivery failures happened frequently enough with the recipient's |
- # email address for Amazon to blacklist it. After a day or three, |
- # they'll be automatically removed, and delivery can be attempted |
- # again (if you write the code to do so in your application). |
- ExceptionToRaise = ses_exceptions.SESAddressBlacklistedError |
- exc_reason = "Address blacklisted." |
- elif "Email address is not verified." in body: |
- # This error happens when the "Reply-To" value passed to |
- # send_email() hasn't been verified yet. |
- ExceptionToRaise = ses_exceptions.SESAddressNotVerifiedError |
- exc_reason = "Email address is not verified." |
- elif "Daily message quota exceeded." in body: |
- # Encountered when your account exceeds the maximum total number |
- # of emails per 24 hours. |
- ExceptionToRaise = ses_exceptions.SESDailyQuotaExceededError |
- exc_reason = "Daily message quota exceeded." |
- elif "Maximum sending rate exceeded." in body: |
- # Your account has sent above its allowed requests a second rate. |
- ExceptionToRaise = ses_exceptions.SESMaxSendingRateExceededError |
- exc_reason = "Maximum sending rate exceeded." |
- elif "Domain ends with dot." in body: |
- # Recipient address ends with a dot/period. This is invalid. |
- ExceptionToRaise = ses_exceptions.SESDomainEndsWithDotError |
- exc_reason = "Domain ends with dot." |
- elif "Local address contains control or whitespace" in body: |
- # I think this pertains to the recipient address. |
- ExceptionToRaise = ses_exceptions.SESLocalAddressCharacterError |
- exc_reason = "Local address contains control or whitespace." |
- elif "Illegal address" in body: |
- # A clearly mal-formed address. |
- ExceptionToRaise = ses_exceptions.SESIllegalAddressError |
- exc_reason = "Illegal address" |
- # The re.search is to distinguish from the |
- # SESAddressNotVerifiedError error above. |
- elif re.search('Identity.*is not verified', body): |
- ExceptionToRaise = ses_exceptions.SESIdentityNotVerifiedError |
- exc_reason = "Identity is not verified." |
- elif "ownership not confirmed" in body: |
- ExceptionToRaise = ses_exceptions.SESDomainNotConfirmedError |
- exc_reason = "Domain ownership is not confirmed." |
- else: |
- # This is either a common AWS error, or one that we don't devote |
- # its own exception to. |
- ExceptionToRaise = self.ResponseError |
- exc_reason = response.reason |
- |
- raise ExceptionToRaise(response.status, exc_reason, body) |
- |
- def send_email(self, source, subject, body, to_addresses, |
- cc_addresses=None, bcc_addresses=None, |
- format='text', reply_addresses=None, |
- return_path=None, text_body=None, html_body=None): |
- """Composes an email message based on input data, and then immediately |
- queues the message for sending. |
- |
- :type source: string |
- :param source: The sender's email address. |
- |
- :type subject: string |
- :param subject: The subject of the message: A short summary of the |
- content, which will appear in the recipient's inbox. |
- |
- :type body: string |
- :param body: The message body. |
- |
- :type to_addresses: list of strings or string |
- :param to_addresses: The To: field(s) of the message. |
- |
- :type cc_addresses: list of strings or string |
- :param cc_addresses: The CC: field(s) of the message. |
- |
- :type bcc_addresses: list of strings or string |
- :param bcc_addresses: The BCC: field(s) of the message. |
- |
- :type format: string |
- :param format: The format of the message's body, must be either "text" |
- or "html". |
- |
- :type reply_addresses: list of strings or string |
- :param reply_addresses: The reply-to email address(es) for the |
- message. If the recipient replies to the |
- message, each reply-to address will |
- receive the reply. |
- |
- :type return_path: string |
- :param return_path: The email address to which bounce notifications are |
- to be forwarded. If the message cannot be delivered |
- to the recipient, then an error message will be |
- returned from the recipient's ISP; this message |
- will then be forwarded to the email address |
- specified by the ReturnPath parameter. |
- |
- :type text_body: string |
- :param text_body: The text body to send with this email. |
- |
- :type html_body: string |
- :param html_body: The html body to send with this email. |
- |
- """ |
- format = format.lower().strip() |
- if body is not None: |
- if format == "text": |
- if text_body is not None: |
- raise Warning("You've passed in both a body and a " |
- "text_body; please choose one or the other.") |
- text_body = body |
- else: |
- if html_body is not None: |
- raise Warning("You've passed in both a body and an " |
- "html_body; please choose one or the other.") |
- html_body = body |
- |
- params = { |
- 'Source': source, |
- 'Message.Subject.Data': subject, |
- } |
- |
- if return_path: |
- params['ReturnPath'] = return_path |
- |
- if html_body is not None: |
- params['Message.Body.Html.Data'] = html_body |
- if text_body is not None: |
- params['Message.Body.Text.Data'] = text_body |
- |
- if(format not in ("text", "html")): |
- raise ValueError("'format' argument must be 'text' or 'html'") |
- |
- if(not (html_body or text_body)): |
- raise ValueError("No text or html body found for mail") |
- |
- self._build_list_params(params, to_addresses, |
- 'Destination.ToAddresses.member') |
- if cc_addresses: |
- self._build_list_params(params, cc_addresses, |
- 'Destination.CcAddresses.member') |
- |
- if bcc_addresses: |
- self._build_list_params(params, bcc_addresses, |
- 'Destination.BccAddresses.member') |
- |
- if reply_addresses: |
- self._build_list_params(params, reply_addresses, |
- 'ReplyToAddresses.member') |
- |
- return self._make_request('SendEmail', params) |
- |
- def send_raw_email(self, raw_message, source=None, destinations=None): |
- """Sends an email message, with header and content specified by the |
- client. The SendRawEmail action is useful for sending multipart MIME |
- emails, with attachments or inline content. The raw text of the message |
- must comply with Internet email standards; otherwise, the message |
- cannot be sent. |
- |
- :type source: string |
- :param source: The sender's email address. Amazon's docs say: |
- |
- If you specify the Source parameter, then bounce notifications and |
- complaints will be sent to this email address. This takes precedence |
- over any Return-Path header that you might include in the raw text of |
- the message. |
- |
- :type raw_message: string |
- :param raw_message: The raw text of the message. The client is |
- responsible for ensuring the following: |
- |
- - Message must contain a header and a body, separated by a blank line. |
- - All required header fields must be present. |
- - Each part of a multipart MIME message must be formatted properly. |
- - MIME content types must be among those supported by Amazon SES. |
- Refer to the Amazon SES Developer Guide for more details. |
- - Content must be base64-encoded, if MIME requires it. |
- |
- :type destinations: list of strings or string |
- :param destinations: A list of destinations for the message. |
- |
- """ |
- |
- if isinstance(raw_message, six.text_type): |
- raw_message = raw_message.encode('utf-8') |
- |
- params = { |
- 'RawMessage.Data': base64.b64encode(raw_message), |
- } |
- |
- if source: |
- params['Source'] = source |
- |
- if destinations: |
- self._build_list_params(params, destinations, |
- 'Destinations.member') |
- |
- return self._make_request('SendRawEmail', params) |
- |
- def list_verified_email_addresses(self): |
- """Fetch a list of the email addresses that have been verified. |
- |
- :rtype: dict |
- :returns: A ListVerifiedEmailAddressesResponse structure. Note that |
- keys must be unicode strings. |
- """ |
- return self._make_request('ListVerifiedEmailAddresses') |
- |
- def get_send_quota(self): |
- """Fetches the user's current activity limits. |
- |
- :rtype: dict |
- :returns: A GetSendQuotaResponse structure. Note that keys must be |
- unicode strings. |
- """ |
- return self._make_request('GetSendQuota') |
- |
- def get_send_statistics(self): |
- """Fetches the user's sending statistics. The result is a list of data |
- points, representing the last two weeks of sending activity. |
- |
- Each data point in the list contains statistics for a 15-minute |
- interval. |
- |
- :rtype: dict |
- :returns: A GetSendStatisticsResponse structure. Note that keys must be |
- unicode strings. |
- """ |
- return self._make_request('GetSendStatistics') |
- |
- def delete_verified_email_address(self, email_address): |
- """Deletes the specified email address from the list of verified |
- addresses. |
- |
- :type email_adddress: string |
- :param email_address: The email address to be removed from the list of |
- verified addreses. |
- |
- :rtype: dict |
- :returns: A DeleteVerifiedEmailAddressResponse structure. Note that |
- keys must be unicode strings. |
- """ |
- return self._make_request('DeleteVerifiedEmailAddress', { |
- 'EmailAddress': email_address, |
- }) |
- |
- def verify_email_address(self, email_address): |
- """Verifies an email address. This action causes a confirmation email |
- message to be sent to the specified address. |
- |
- :type email_adddress: string |
- :param email_address: The email address to be verified. |
- |
- :rtype: dict |
- :returns: A VerifyEmailAddressResponse structure. Note that keys must |
- be unicode strings. |
- """ |
- return self._make_request('VerifyEmailAddress', { |
- 'EmailAddress': email_address, |
- }) |
- |
- def verify_domain_dkim(self, domain): |
- """ |
- Returns a set of DNS records, or tokens, that must be published in the |
- domain name's DNS to complete the DKIM verification process. These |
- tokens are DNS ``CNAME`` records that point to DKIM public keys hosted |
- by Amazon SES. To complete the DKIM verification process, these tokens |
- must be published in the domain's DNS. The tokens must remain |
- published in order for Easy DKIM signing to function correctly. |
- |
- After the tokens are added to the domain's DNS, Amazon SES will be able |
- to DKIM-sign email originating from that domain. To enable or disable |
- Easy DKIM signing for a domain, use the ``SetIdentityDkimEnabled`` |
- action. For more information about Easy DKIM, go to the `Amazon SES |
- Developer Guide |
- <http://docs.amazonwebservices.com/ses/latest/DeveloperGuide>`_. |
- |
- :type domain: string |
- :param domain: The domain name. |
- |
- """ |
- return self._make_request('VerifyDomainDkim', { |
- 'Domain': domain, |
- }) |
- |
- def set_identity_dkim_enabled(self, identity, dkim_enabled): |
- """Enables or disables DKIM signing of email sent from an identity. |
- |
- * If Easy DKIM signing is enabled for a domain name identity (e.g., |
- * ``example.com``), |
- then Amazon SES will DKIM-sign all email sent by addresses under that |
- domain name (e.g., ``user@example.com``) |
- * If Easy DKIM signing is enabled for an email address, then Amazon SES |
- will DKIM-sign all email sent by that email address. |
- |
- For email addresses (e.g., ``user@example.com``), you can only enable |
- Easy DKIM signing if the corresponding domain (e.g., ``example.com``) |
- has been set up for Easy DKIM using the AWS Console or the |
- ``VerifyDomainDkim`` action. |
- |
- :type identity: string |
- :param identity: An email address or domain name. |
- |
- :type dkim_enabled: bool |
- :param dkim_enabled: Specifies whether or not to enable DKIM signing. |
- |
- """ |
- return self._make_request('SetIdentityDkimEnabled', { |
- 'Identity': identity, |
- 'DkimEnabled': 'true' if dkim_enabled else 'false' |
- }) |
- |
- def get_identity_dkim_attributes(self, identities): |
- """Get attributes associated with a list of verified identities. |
- |
- Given a list of verified identities (email addresses and/or domains), |
- returns a structure describing identity notification attributes. |
- |
- :type identities: list |
- :param identities: A list of verified identities (email addresses |
- and/or domains). |
- |
- """ |
- params = {} |
- self._build_list_params(params, identities, 'Identities.member') |
- return self._make_request('GetIdentityDkimAttributes', params) |
- |
- def list_identities(self): |
- """Returns a list containing all of the identities (email addresses |
- and domains) for a specific AWS Account, regardless of |
- verification status. |
- |
- :rtype: dict |
- :returns: A ListIdentitiesResponse structure. Note that |
- keys must be unicode strings. |
- """ |
- return self._make_request('ListIdentities') |
- |
- def get_identity_verification_attributes(self, identities): |
- """Given a list of identities (email addresses and/or domains), |
- returns the verification status and (for domain identities) |
- the verification token for each identity. |
- |
- :type identities: list of strings or string |
- :param identities: List of identities. |
- |
- :rtype: dict |
- :returns: A GetIdentityVerificationAttributesResponse structure. |
- Note that keys must be unicode strings. |
- """ |
- params = {} |
- self._build_list_params(params, identities, |
- 'Identities.member') |
- return self._make_request('GetIdentityVerificationAttributes', params) |
- |
- def verify_domain_identity(self, domain): |
- """Verifies a domain. |
- |
- :type domain: string |
- :param domain: The domain to be verified. |
- |
- :rtype: dict |
- :returns: A VerifyDomainIdentityResponse structure. Note that |
- keys must be unicode strings. |
- """ |
- return self._make_request('VerifyDomainIdentity', { |
- 'Domain': domain, |
- }) |
- |
- def verify_email_identity(self, email_address): |
- """Verifies an email address. This action causes a confirmation |
- email message to be sent to the specified address. |
- |
- :type email_adddress: string |
- :param email_address: The email address to be verified. |
- |
- :rtype: dict |
- :returns: A VerifyEmailIdentityResponse structure. Note that keys must |
- be unicode strings. |
- """ |
- return self._make_request('VerifyEmailIdentity', { |
- 'EmailAddress': email_address, |
- }) |
- |
- def delete_identity(self, identity): |
- """Deletes the specified identity (email address or domain) from |
- the list of verified identities. |
- |
- :type identity: string |
- :param identity: The identity to be deleted. |
- |
- :rtype: dict |
- :returns: A DeleteIdentityResponse structure. Note that keys must |
- be unicode strings. |
- """ |
- return self._make_request('DeleteIdentity', { |
- 'Identity': identity, |
- }) |
- |
- def set_identity_notification_topic(self, identity, notification_type, sns_topic=None): |
- """Sets an SNS topic to publish bounce or complaint notifications for |
- emails sent with the given identity as the Source. Publishing to topics |
- may only be disabled when feedback forwarding is enabled. |
- |
- :type identity: string |
- :param identity: An email address or domain name. |
- |
- :type notification_type: string |
- :param notification_type: The type of feedback notifications that will |
- be published to the specified topic. |
- Valid Values: Bounce | Complaint | Delivery |
- |
- :type sns_topic: string or None |
- :param sns_topic: The Amazon Resource Name (ARN) of the Amazon Simple |
- Notification Service (Amazon SNS) topic. |
- """ |
- params = { |
- 'Identity': identity, |
- 'NotificationType': notification_type |
- } |
- if sns_topic: |
- params['SnsTopic'] = sns_topic |
- return self._make_request('SetIdentityNotificationTopic', params) |
- |
- def set_identity_feedback_forwarding_enabled(self, identity, forwarding_enabled=True): |
- """ |
- Enables or disables SES feedback notification via email. |
- Feedback forwarding may only be disabled when both complaint and |
- bounce topics are set. |
- |
- :type identity: string |
- :param identity: An email address or domain name. |
- |
- :type forwarding_enabled: bool |
- :param forwarding_enabled: Specifies whether or not to enable feedback forwarding. |
- """ |
- return self._make_request('SetIdentityFeedbackForwardingEnabled', { |
- 'Identity': identity, |
- 'ForwardingEnabled': 'true' if forwarding_enabled else 'false' |
- }) |