#python #amazon-web-services #post #python-requests #amazon-ses
#python #amazon-web-services #Публикация #python-запросы #amazon-ses
Вопрос:
Это код запроса get, который я в настоящее время использую для отправки электронной почты через простой почтовый сервис Amazon:
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'
'amp;Destination.ToAddresses.member.1={}'
'amp;Message.Body.Html.Charset=UTF-8'
'amp;Message.Body.Html.Data={}'
'amp;Message.Body.Text.Charset=UTF-8'
'amp;Message.Body.Text.Data={}'
'amp;Message.Subject.Charset=UTF-8'
'amp;Message.Subject.Data={}'
'amp;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 = 'amp;X-Amz-Algorithm=AWS4-HMAC-SHA256'
canonical_querystring_part2 = 'amp;X-Amz-Credential=' urllib.parse.quote_plus(access_key '/' credential_scope)
canonical_querystring_part2 = 'amp;X-Amz-Date=' amz_date
canonical_querystring_part2 = 'amp;X-Amz-Expires=30'
canonical_querystring_part2 = 'amp;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 = 'amp;X-Amz-Signature=' signature
request_url = endpoint "?" canonical_querystring
r = requests.get(request_url)
Это немного длинновато, но выполняется нормально. Это моя попытка сделать то же самое, но с запросом post:
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 в моем запросе post с 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 '?'): '/?{'body': {'Action': 'SendEmail', 'Destination.ToAddresses.member.1': 'ArbiBushka717@gmail.com', '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': 'ArbiBushka717@gmail.com'}, 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'context': {'client_region': 'us-east-1'}}'</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>
Каждая форма запроса post выдает различную ошибку. Кто-нибудь, имеющий опыт структурирования запросов post (или запросов к API Amazon), знает, что я делаю неправильно?
Прежде чем кто-либо напишет: «Используйте их Python SDK». Я не могу. Их SDK блокируется, и я должен делать это асинхронно. Я планирую перейти от запросов к aiohttp. Я пытаюсь получить это в запросах на данный момент, потому что так проще задать этот вопрос.
Пожалуйста, помогите, если можете, спасибо за чтение.
Комментарии:
1. Будет очень полезно, если вы сможете опубликовать фактические тела запросов
Ответ №1:
подождите nvm, я должен. Чтобы указать тело в запросах, вы используете kwarg «data».
Также моя переменная request_parameters
должна была быть в формате param1=Thisamp;param2=that
Вау, какая головная боль.