Это код запроса на получение, который я сейчас использую для отправки электронного письма через сервис электронной почты Amazon Simple:
import datetime
import hashlib
import hmac
import urllib.parse
import requests
def sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def getSignatureKey(key, dateStamp, regionName, serviceName):
kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName)
kSigning = sign(kService, 'aws4_request')
return kSigning
method = 'GET'
service = 'ses'
host = 'email.us-east-1.amazonaws.com'
region = 'us-east-1'
endpoint = 'https://email.us-east-1.amazonaws.com/'
access_key = 'my_access_key'
secret_key = 'my_secret_key'
my_email = 'my_email_address'
t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d')
canonical_uri = '/'
canonical_headers = 'host:' + host + '\n'
signed_headers = 'host'
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
canonical_querystring_part1 = 'Action=SendEmail' \
'&Destination.ToAddresses.member.1={}' \
'&Message.Body.Html.Charset=UTF-8' \
'&Message.Body.Html.Data={}' \
'&Message.Body.Text.Charset=UTF-8' \
'&Message.Body.Text.Data={}' \
'&Message.Subject.Charset=UTF-8' \
'&Message.Subject.Data={}' \
'&Source={}'.format(urllib.parse.quote(my_email, safe=''),
urllib.parse.quote('<b>Html Hello.</b>', safe=''),
urllib.parse.quote('Non Html hello.', safe=''),
urllib.parse.quote('Asyncio Subject line.', safe=''),
urllib.parse.quote(my_email, safe=''))
canonical_querystring_part2 = '&X-Amz-Algorithm=AWS4-HMAC-SHA256'
canonical_querystring_part2 += '&X-Amz-Credential=' + urllib.parse.quote_plus(access_key + '/' + credential_scope)
canonical_querystring_part2 += '&X-Amz-Date=' + amz_date
canonical_querystring_part2 += '&X-Amz-Expires=30'
canonical_querystring_part2 += '&X-Amz-SignedHeaders=' + signed_headers
canonical_querystring = canonical_querystring_part1 + canonical_querystring_part2
payload_hash = hashlib.sha256(''.encode('utf-8')).hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
signing_key = getSignatureKey(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
canonical_querystring += '&X-Amz-Signature=' + signature
request_url = endpoint + "?" + canonical_querystring
r = requests.get(request_url)
Это немного долго, но работает нормально. Это моя попытка сделать то же самое, но с почтовым запросом:
import datetime
import hashlib
import hmac
import requests
def sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def getSignatureKey(key, dateStamp, regionName, serviceName):
kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName)
kSigning = sign(kService, 'aws4_request')
return kSigning
method = 'POST'
service = 'ses'
host = 'email.us-east-1.amazonaws.com'
region = 'us-east-1'
endpoint = 'https://email.us-east-1.amazonaws.com/'
access_key = 'my_access_key'
secret_key = 'my_secret_key'
my_email = 'my_email_address'
content_type = 'application/x-www-form-urlencoded; charset=utf-8'
# Request parameters for CreateTable--passed in a JSON block.
request_parameters = '{'
request_parameters += "'body': {'Action': 'SendEmail', 'Destination.ToAddresses.member.1': '%s', 'Message.Body.Html.Charset': 'UTF-8', " \
"'Message.Body.Html.Data': 'HTMLMESSAGE', 'Message.Body.Text.Charset': 'UTF-8', 'Message.Body.Text.Data': 'nonHTMLmessage', 'Message.Subject.Charset': 'UTF-8', " \
"'Message.Subject.Data': 'subject','Source': '%s'}, " % (my_email, my_email)
request_parameters += "'Content-Type': '%s', " % content_type
request_parameters += "'context': {'client_region': 'us-east-1'}"
request_parameters += '}'
t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
date_stamp = t.strftime('%Y%m%d')
canonical_uri = '/'
canonical_querystring = ''
canonical_headers = 'content-type:' + content_type + '\n' + 'host:' + host + '\n' + 'x-amz-date:' + amz_date + '\n'
signed_headers = 'content-type;host;x-amz-date'
payload_hash = hashlib.sha256(request_parameters.encode('utf-8')).hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
signing_key = getSignatureKey(secret_key, date_stamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = {'Content-Type': content_type, 'X-Amz-Date': amz_date, 'Authorization': authorization_header}
r = requests.post(endpoint, params=request_parameters, headers=headers)
Я следую документации Amazon как можно лучше для процесса подписания v4 здесь: https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
Я также использую полные примеры запросов get и post, которые они имеют для SES, найденные здесь: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-examples.html
По какой-то причине это не работает. Я попытался изменить kwarg в своем почтовом запросе с params на json и data.
r = requests.post(endpoint, params=request_parameters, headers=headers)
<IncompleteSignatureException>
<Message>When Content-Type:application/x-www-form-urlencoded, URL cannot include query-string parameters (after '?'): '/?%7B'body':%20%7B'Action':%20'SendEmail',%20'Destination.ToAddresses.member.1':%20'ArbiBushka717@gmail.com',%20'Message.Body.Html.Charset':%20'UTF-8',%20'Message.Body.Html.Data':%20'HTMLMESSAGE',%20'Message.Body.Text.Charset':%20'UTF-8',%20'Message.Body.Text.Data':%20'nonHTMLmessage',%20'Message.Subject.Charset':%20'UTF-8',%20'Message.Subject.Data':%20'subject','Source':%20'ArbiBushka717@gmail.com'%7D,%20'Content-Type':%20'application/x-www-form-urlencoded;%20charset=utf-8',%20'context':%20%7B'client_region':%20'us-east-1'%7D%7D'</Message>
</IncompleteSignatureException>
r = requests.post(endpoint, data=request_parameters, headers=headers)
<AccessDeniedException/>
r = requests.post(endpoint, json=request_parameters, headers=headers)
<InvalidSignatureException>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</InvalidSignatureException>
Каждая форма почтового запроса дает различную ошибку. Кто-нибудь с опытом структурирования почтовых запросов (или запросов к API Amazon) знает, что я делаю неправильно?
Прежде чем кто-либо напишет: «Используйте свой Python SDK». Я не могу Их SDK блокирует, и я должен сделать это асинхронно. Я планирую перейти от запросов к aiohttp. Я пытаюсь получить это в запросах на данный момент, потому что этот вопрос проще задать.
Пожалуйста, помогите, если можете, спасибо за чтение.