Cloud DevOps Cookbook Part 4-Explore DevOps DirectMail in Python with REST API

This time, we will explore ** Direct Mail ** of ** Alibaba Cloud DevOps ** using ** REST API ** with ** Python **.

Alibaba Cloud Tech Share, author John Hanley. Tech Share encourages sharing of technical knowledge and best practices within the cloud community Alibaba Cloud Incentive program.

My favorite language for learning rapid prototyping and new cloud services is Python. With Python, most tasks are so simple that you can test your new API in minutes. This allows you to focus on learning without having to worry about the details of how the API works in a particular language. But I'm using C ++ for enterprise-level code that can cost millions of dollars if I make a mistake.

Alibaba's DirectMail does not support Python. PHP, Java and C # are supported. A very common use case for DirectMail is to email dynamic and static websites. Is to deliver. For dynamic websites, PHP is the best choice. For static websites, DirectMail and [Function Compute](https://www.alibabacloud.com/ Integrating product / function-compute? Spm = a2c65.11461447.0.0.38ad725bFhEjCQ) is perfect. However, Function Compute does not support PHP. This means developing in one language on the desktop and in another on the cloud.

So I came up with the idea of using DirectMail's REST API. That means you can use Python to learn how to use the REST API and especially how to create less documented signatures.

DirectMail supports three different interfaces (not all languages are supported).

1、Alibaba REST API 2、Alibaba Cloud SDK 3、Alibaba SMTP Interface In the previous article, I introduced an example of using SDK (Function Compute) in Python. This time, I will focus on the DirectMail REST API and show an example of how it works in Python.

Alibaba Cloud DirectMail REST API

There are several reasons to use the REST API.

  1. Understand low-level APIs, parameters and errors. 2, the code space is small. 3, shortened loading and execution time. 4, there are few dependencies.
  2. No need to install SDK library on target system. 6, SDK is not available in the target language.

REST API requirements

  1. Understand HTTPS, HTTP headers, and HTTP bodies.
  2. Understand the difference between HTTP HEAD, DELETE, GET, POST and PUT methods.
  3. Understand how to send data for each HTTP method.
  4. Understand the API parameters that each HTTP method must contain.
  5. Understand how to sign HTTP requests.

Alibaba Cloud Public Parameters

This is a link to Alibaba Documentation for DirectMail Public Parameters.

name type Is it mandatory Explanation
Format String No The type of response value. JSON and XML are supported. XML is the default format. This example uses JSON.
Version String Yes API version number. The format is YYYY-MM-It is DD. RegionID is cn-For hangzhou, the version number is 2015-11-twenty three. RegionID is cn-If it is not hangzhou, the version number is ap-southeast-2017 for 1 etc.-06-It's 22. In the example 2017-06-Use 22.
AccessKeyId String Yes AccessKeyId issued by Alibaba Cloud to users to access the service.
SecurityToken String Depends This parameter is not required if you are using the access key defined for the user. If you are using roles, context.A security token passed to the function as part of the credentials object.
Signature String Yes The character string of the signature result. For details on how to calculate the signature, see "Signature"Please refer to.
SignatureMethod String Yes Signing method. HMAC-SHA1 is currently supported.
Timestamp String Yes Request time stamp. The date format isISO8601ItconformstothestandardandadoptsUTCtime.Theformatisasfollows.YYYY-MM-DDThh:mm:ssZ.Example:2015-11-23T04:00:00Z(BeijingTimeNovember23,201512:00:For00).
SignatureVersion String Yes The version of the signature algorithm. Current version is 1.It is 0.
SignatureNonce String Yes Unique random number. Used to prevent replay attacks. You must use a different random number for each request.
RegionId String Yes Data center information. cn-hangzhou、ap-southeast-1、ap-southeast-2 is currently supported.

Comments on the above parameters:

** SignatureNonce **: This parameter has been annoying for some time. At first I thought this was the salt value used when signing HMAC_SHA1. However, it turns out that this is a string generated by uuid.uuid4 () and contained in the header. Repeating the value of this string in a subsequent command will reject the command.

** AccessKeyId **: Creates a new RAM user with DirectMail-only permissions. In this case, you will need both an Access Key and an Access Key Secret for the REST API.

** Timestamp **: It is important that the system date and time are correct. If this time is different from Alibaba's service, the request will be rejected. If possible, use a time service such as NTP for your system.

Alibaba Cloud Direct Mail request parameters

This is a link to Alibaba documentation on DirectMail Request parameters.

name type Is it mandatory Explanation
Action String Required Operation interface name and system required parameters. Specify the value. Single Send Mail.
AccountName String Required The sender address configured in the console.
ReplyToAddress Boolean Required The reply address configured in the console (status must be "verified").
AddressType Number Required Range of values: 0-1. 0 indicates a random account and 1 indicates the sender address.
ToAddress String Required Recipient's address. Multiple addresses can be separated by commas and support up to 100 addresses.
FromAlias String option Sender's nickname. Nicknames must be 15 characters or less in length. For example, the sender's nickname is set to Daisy and the sender's address is [email protected] is com. The recipient is Daisy[email protected]Refer to the address of.
Subject String Optional Subject (Recommendation)。
HtmlBody String Optional Display the email body in HTML.
TextBody String Optional Display the body of the email as text.
ClickTrace String Optional Range of values. 0-1. 1 indicates that recipient tracking is enabled. 0 indicates that recipient tracking is not enabled. The default value for this parameter is 0.

Calculate the correct date

# Correctly formatted date and time
now = datetime.datetime.utcnow()

# Date used by the HTTP "Date" header
date = now.strftime("%a, %d %b %Y %H:%M:%S GMT")

# Date used by the API parameter "Timestamp"
utc = now.isoformat(timespec='seconds') + 'Z'

Hosts and endpoints in this example (Singapore-> ap-southeast-1)

# HTTP Host header
host = "dm.ap-southeast-1.aliyuncs.com"

# URL for POST
url = "https://dm.ap-southeast-1.aliyuncs.com/"

Building a parameter list of public parameters

parameters = {}

# Add the DirectMail public request parameters
parameters["Format"] = "json"
parameters["AccessKeyId"] = credentials['AccessKey']
parameters["SignatureMethod"] = "HMAC-SHA1"
parameters["SignatureType"] = ""
parameters["SignatureVersion"] = "1.0"
parameters["SignatureNonce"] = get_uuid()
parameters["Timestamp"] = utc
parameters["Version"] = "2017-06-22"
parameters["RegionId"] = "ap-southeast-1"

Building a parameter list of request parameters

# Add parameters that are always set
parameters["Action"] = "SingleSendMail"
parameters["AddressType"] = "1"
parameters["ReplyToAddress"] = "true"

# Add the DirectMail API parameters
parameters["AccountName"] = dm_account
parameters["FromAlias"] = dm_alias
parameters["ToAddress"] = to_list
parameters["Subject"] = subject
parameters["HtmlBody"] = body
parameters["textBody"] = body_text

Build request string for signature processing

def build_request_string(table):
    """ Build canonical list """
    items = sorted(iter(table.items()), key=lambda d: d[0])
    enc = my_urlencode(items)
    return enc

Precautions regarding request string

Request string parameters must be sorted first. The string is then url-encoded. This means that each key / value pair will have an & character.

The final result looks like the example below, but with a longer length.

AccessKeyId=LTAIQlgy6erobert&AccountName=test%40test.com&Action=SingleSendMail …

Create a signature from the request string

This is a link to Alibaba Documentation on DirectMail Signature.

# Build the request string for the signing process
params = build_request_string(parameters)

# Create the actual string to sign (method = "POST")
stringToSign = method + "&%2F&" + percentEncode(params)

Signature = sign(stringToSign, credentials['AccessKeySecret'])

A program that calls the DirectMail REST API to send an email

Download sendEmail.zip.

############################################################
# Version 1.00
# Date Created: 2018-05-26
# Last Update:  2018-05-27
# https://www.neoprime.io
# Copyright (c) 2018, NeoPrime, LLC
############################################################

""" Alibaba Cloud DirectMail REST API With Signing """

import base64
import datetime
import hmac
import hashlib
import urllib
import uuid
import json
import requests

# My library for processing Alibaba Cloud Services (ACS) credentials
import mycred_acs

# From the DirectMail Console
dm_account = "<enter your value here>"
dm_alias = "<enter your value here>"

debug = 0

def set_connection_logging():
    """ Enable HTTP connection logging """
    if debug is 0:
        return

    import logging
    import http.client as http_client

    http_client.HTTPConnection.debuglevel = 1

    # You must initialize logging, otherwise you'll not see debug output.
    logging.basicConfig()
    logging.getLogger().setLevel(logging.DEBUG)
    requests_log = logging.getLogger("requests.packages.urllib3")
    requests_log.setLevel(logging.DEBUG)
    requests_log.propagate = True
    return

def get_uuid():
    """ return a uuid as a signing nonce """
    return str(uuid.uuid4())

def percentEncode(path):
    """ Encode a URL """
    res = urllib.parse.quote(path)
    res = res.replace('+', '%20')
    res = res.replace('*', '%2A')
    res = res.replace('%7E', '~')
    return res

def my_urlencode(query):
    """ Encode a Query """
    res = urllib.parse.urlencode(query)
    res = res.replace('+', '%20')
    res = res.replace('*', '%2A')
    res = res.replace('%7E', '~')
    return res

def build_request_string(table):
    """ Build canonical list """
    items = sorted(iter(table.items()), key=lambda d: d[0])
    enc = my_urlencode(items)
    return enc

def sign(string, secret):
    """ Sign REST API Request """
    nsecret = secret + '&'

    h = hmac.new(
        bytes(nsecret, "utf-8"),
        bytes(string, "utf-8"),
        hashlib.sha1)

    #sig = base64.b64encode(h.digest())
    sig = str(base64.encodebytes(h.digest()).strip(), "utf-8")
    return sig

def sendEmail(credentials, subject, body, body_text, to_list):
    """ Send an email using Alibaba DirectMail """
    # HTTP Method
    method = "POST"

    # Correctly formatted date and time
    now = datetime.datetime.utcnow()
    date = now.strftime("%a, %d %b %Y %H:%M:%S GMT")
    utc = now.isoformat(timespec='seconds') + 'Z'

    # HTTP Host header
    host = "dm.ap-southeast-1.aliyuncs.com"

    # URL for POST
    url = "https://dm.ap-southeast-1.aliyuncs.com/"

    parameters = {}

    # Add the DirectMail public request parameters
    parameters["Format"] = "json"
    parameters["AccessKeyId"] = credentials['AccessKey']
    parameters["SignatureMethod"] = "HMAC-SHA1"
    parameters["SignatureType"] = ""
    parameters["SignatureVersion"] = "1.0"
    parameters["SignatureNonce"] = get_uuid()
    parameters["Timestamp"] = utc
    #parameters["Version"] = "2015-11-23"
    parameters["Version"] = "2017-06-22"
    parameters["RegionId"] = "ap-southeast-1"

    # Add parameters that are always set
    parameters["Action"] = "SingleSendMail"
    parameters["AddressType"] = "1"
    parameters["ReplyToAddress"] = "true"

    # Add the DirectMail API parameters
    parameters["AccountName"] = dm_account
    parameters["FromAlias"] = dm_alias
    parameters["ToAddress"] = to_list
    parameters["Subject"] = subject
    parameters["HtmlBody"] = body
    parameters["textBody"] = body_text

    # Build the request string for the signing process
    params = build_request_string(parameters)

    # Create the actual string to sign
    stringToSign = method + "&%2F&" + percentEncode(params)

    #print("String to Sign")
    #print(stringToSign)

    Signature = sign(stringToSign, credentials['AccessKeySecret'])
    #print("Signature", Signature)

    parameters["Signature"] = Signature

    headers = {
        'Date': date,
        'Host': host
    }

    set_connection_logging()

    print("Sending Email to", parameters["ToAddress"])
    r = requests.post(url, data=parameters, headers=headers)

    if r.status_code != 200:
        print("Error: Email Send Failed:", r.status_code)
        print(r.text)
        return 1

    #print(r.text)

    result = json.loads(r.text)
    print("Success: Request ID:", result['RequestId'])

    return 0

# Load the Alibaba Cloud Credentials (AccessKey)
cred = mycred_acs.LoadCredentials()

dm_subject = "Welcome to Alibaba Cloud DirectMail"

dm_body = "<h2>Welcome to Alibaba Cloud DirectMail<h2>You are receiving this email as part of a test program.<br /><br />Click for <a href='https://www.neoprime.io/info/alibaba/'>more information<a>.<br /><br /><a href='https://www.alibabacloud.com/'><img src='https://www.neoprime.io/info/alibaba/img/alibaba-600x263.png' alt='Alibaba' width='700'><a>"

dm_body_text = "Welcome to Alibaba Cloud DirectMail\nYou are receiving this email as part of a test program."

dm_to_list = "[email protected], [email protected]

sendEmail(cred, dm_subject, dm_body, dm_body_text, dm_to_list)

Run on Python 3.x: python sendEmail.py

Alibaba document

Alibaba DirectMail Product Page Alibaba DirectMail Documentation Alibaba DirectMail Public parameters Alibaba DirectMail Request parameters Alibaba DirectMail Signature

Recommended Posts

Cloud DevOps Cookbook Part 4-Explore DevOps DirectMail in Python with REST API
Quickly implement REST API in Python
Text extraction with GCP Cloud Vision API (Python3.6)
[WP REST API v2] Upload images in Python
[Cloud102] # 1 Get Started with Python (Part 1 Python First Steps)
Python beginners tried implementing REST API in one day
Playing with a user-local artificial intelligence API in Python
Get LEAD data using Marketo's REST API in Python
Evernote API in Python
Explore Alibaba Cloud Function Compute for DevOps using Python 3.0
C API in Python 3
Easy to use Nifty Cloud API with botocore and python
Flow of extracting text in PDF with Cloud Vision API
The first API to make with python Djnago REST framework
[SAP CP] Web API created with python in CF environment
Specification generation and code generation in REST API development (Python edition)
Issue reverse geocoding in Japanese with Python Google Maps API
Hit Mastodon's API in Python
Image processing with Python (Part 2)
Studying Python with freeCodeCamp part1
Use Trello API with python
Bordering images with python Part 1
Scraping with selenium in Python
Scraping with Selenium + Python Part 1
Working with LibreOffice in Python
Scraping with chromedriver in python
Use Twitter API with Python
Debugging with pdb in Python
Working with sounds in Python
Scraping with Selenium in Python
Studying Python with freeCodeCamp part2
Image processing with Python (Part 1)
Scraping with Tor in Python
Web API with Python + Falcon
Tweet with image in Python
Solving Sudoku with Python (Part 2)
Combined with permutations in Python
Image processing with Python (Part 3)
UI Automation Part 2 in Python
Play RocketChat with API / Python
Scraping with Selenium + Python Part 2
Blender Python API in Houdini (Python 3)
Call the API with python3.
Use subsonic API with python3
Operate Jupyter with REST API to extract and save Python code
A story about adding a REST API to a daemon made with Python
Implementation of CRUD using REST API with Python + Django Rest framework + igGrid
Create REST API that returns the current time with Python3 + Falcon
Visualize the frequency of word occurrences in sentences with Word Cloud. [Python]
Image upload & download to Azure Storage. With Python + requests + REST API
Firebase Authentication token issuance in Python and token verification with Fast API
LINE BOT (Messaging API) development with API Gateway and Lambda (Python) [Part 2]
I tried to refactor the template code posted in "Getting images from Flickr API with Python" (Part 2)
Number recognition in images with Python
Playing handwritten numbers with python Part 1
[Package cloud] Manage python packages with package cloud
Testing with random numbers in Python
Getting the arXiv API in Python
Create Awaitable with Python / C API
Working with LibreOffice in Python: import
Get reviews with python googlemap api