All Products
Search
Document Center

Direct Mail:Request signatures

Last Updated:Jun 02, 2026

Direct Mail authenticates every API request with an HMAC-SHA1 signature derived from your AccessKey pair.

Note:

  • Skip this topic if you use an Alibaba Cloud SDK (available for Java, PHP, and C#).

  • The API supports GET and POST requests, but the StringToSign differs between them.

Every request must include a signature, whether sent over HTTP or HTTPS. Direct Mail uses an AccessKey ID and AccessKey secret to verify the sender. You can manage your AccessKey pairs in the User Information Management console. The AccessKey ID identifies the requester; the AccessKey secret signs the request and verifies it server-side. Keep your AccessKey secret confidential.

Signature steps

To sign a request:

  1. Create a canonicalized query string from the request parameters.

    a. Sort the parameters.

    Sort all request parameters (common and API-specific) alphabetically by name. Exclude the Signature parameter.

    Note: For GET requests, these parameters are the part of the request URL that follows the ? and are separated by &.

    b. Encode each parameter name and value.

    URL-encode names and values with UTF-8. Rules:

    • Do not encode A-Z, a-z, 0-9, -, _, ., or ~.

    • Encode other characters as %XY, where XY is the hex ASCII value. Example: "%22.

    • Encode multi-byte UTF-8 characters as %XY%ZA….

    • Encode spaces as %20, not +.

    Important: Standard URL-encoding libraries (such as java.net.URLEncoder) follow application/x-www-form-urlencoded rules. After encoding, replace + with %20, * with %2A, and %7E with ~.

    c. Join each encoded name and value with =.

    d. Join all name-value pairs with & in the sorted order from step a. This produces the canonicalized query string.

  2. Create the string-to-sign in the following format:

     StringToSign=
     HTTPMethod + "&" +
     percentEncode("/") + "&" +
     percentEncode(CanonicalizedQueryString)        

    HTTPMethod is the HTTP method (GET or POST).

    percentEncode("/") encodes / per the rules in step 1.b, yielding %2F.

    percentEncode(CanonicalizedQueryString) encodes the canonicalized query string from step 1 per the rules in step 1.b. Note: This produces a double-encoded result.

  3. Calculate the HMAC value.

    Compute the HMAC-SHA1 of the StringToSign as defined in RFC2104.

    Note: The signing key is your AccessKeySecret followed by & (ASCII 38). The hash algorithm is SHA1.

  4. Calculate the signature value.

    Base64-encode the HMAC value from step 3. The result is the signature.

  5. Add the signature to the request as the Signature parameter.

    Note: The Signature value must be URL-encoded like other parameters, per RFC3986.

Signature example

This example signs a SingleSendMail POST request.

Request URL: http://dm.aliyuncs.com/

Request parameters:

AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23

StringToSign:

POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23

With AccessKeyId testid and AccessKeySecret testsecret, the signing key is testsecret&. The resulting signature:

llJfXJjBW3OacrVgxxsITgYaYm0=

The signed POST body (with Signature added and Content-Type set to application/x-www-form-urlencoded):

Signature=llJfXJjBW3OacrVgxxsITgYaYm0=&AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23

These parameters must be URL-encoded before sending..

Code examples

Java

private static final String MAC_NAME ="HmacSHA1";
private static final String ENCODING ="UTF-8";

/**
 * Signs encryptText using the HMAC-SHA1 method.
 *
 *@param encryptText The string to be signed.
 *@param encryptKey  The key.
 *@return
 *@throws Exception
 */
public static byte[] HmacSHA1Encrypt(StringencryptText, String encryptKey) throwsException {
byte[] data = encryptKey.getBytes(ENCODING);
// Creates a key from the given byte array. The second parameter specifies the name of the key algorithm.
SecretKey secretKey = new SecretKeySpec(data,MAC_NAME);
// Generates a Mac object for the specified Mac algorithm.
Mac mac = Mac.getInstance(MAC_NAME);
// Initializes the Mac object with the given key.
mac.init(secretKey);
byte[] text = encryptText.getBytes(ENCODING);
// Completes the Mac operation.
return mac.doFinal(text);
}
@Test
public void test() throws Exception {
/*StringToSign=
                HTTPMethod + “&” +
                percentEncode(“/”) + ”&” +
percentEncode(CanonicalizedQueryString)*/
String str ="AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC"+
"-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23";
String percentStr = "";
String[] strs = str.split("&");
for (int i = 0; i < strs.length;i++) {
String[] str1 =strs[i].split("=");
if (str1.length == 1){
                percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder("")+ "&";
}else {
                percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder(str1[1]) + "&";
            }
}
percentStr =percentStr.substring(0,percentStr.lastIndexOf("&"));
String percent = URLEncoder.encode("/","UTF-8");
percentStr = getUtf8Encoder(percentStr);
String toSign = HttpMethod.POST + "&"+ percent +"&" + percentStr;
System.out.println("--------------"+ toSign);
/*POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23*/
byte[] bytes = HmacSHA1Encrypt(toSign,"testsecret&");
String base64Str = Base64.encode(bytes);
System.out.println(base64Str);//llJfXJjBW3OacrVgxxsITgYaYm0=
}
private String getUtf8Encoder(String param) throwsUnsupportedEncodingException {
return URLEncoder.encode(param, "UTF-8")
                .replaceAll("\\+","%20")
                .replaceAll("\\*","%2A")
                .replaceAll("%7E","~");
 };

Python

import hmac
import base64
# Replace StringToSign with the actual content.
message = b'StringToSign'
key = b'testsecret&'
h = hmac.new(key, message, digestmod='sha1')
# print(h.digest())
print(base64.b64encode(h.digest()))

PHP

<?php
function encryptTokey($data){
     $apikey = 'testsecret&';
     $sign = base64_encode(hash_hmac("sha1", $data, $apikey, true));
     //printf($sign);
     return $sign;
}
// Replace StringToSign with the actual content.
echo encryptTokey(StringToSign);
?>

FAQ

  • Intermittent SignatureDoesNotMatch errors typically mean special characters were not replaced after encoding. See the Important note above.

  • For unresolved signature mismatch issues, use the Request example and substitute your own parameters.