阿里云邮件推送服务Python API发送邮件

使用SMTP发送邮件不显示发件人名字,就很不爽,于是读了读API,换用API发送邮件。具体参考文档:https://help.aliyun.com/document_detail/29442.html

官方说参数还要按字典序排序就很烦。FromAlias参数可以显示发件人名字。签名过程也是试了又试才成功了。具体代码如下

后来发现还有空格编码的问题

import time
from urllib import parse,request
import hmac
import base64
from datetime import datetime, timedelta

def get_UTC():
    #UTC时间
    now_time = datetime.now()
    utc_time = now_time - timedelta(hours=8)              # UTC只是比北京时间提前了8个小时
    utc_time = utc_time.strftime("%Y-%m-%dT%H:%M:%SZ")    # 转换成Aliyun要求的传参格式...
    return utc_time

#特别注意:一般支持 URL 编码的库(比如 Java 中的 java.net.URLEncoder)都
# 是按照 application/x-www-form-urlencoded 的 MIME 类型的规则进行编码。可以直接使用这类方式进行编码,
# 把编码后的字符串中加号 + 替换成 %20、星号 * 替换成 %2A、%7E 替换回波浪号 ~,
# 即可得到上述规则描述的编码字符串。
def updateEncode(txt):
    ret=txt.replace("+","%20")
    ret=ret.replace("*","%2A")
    ret=ret.replace("%7E","~")
    return ret

def sendMail(subject,content):
    utc_time=get_UTC()
    parm={
        "Version":"2015-11-23",
        "AccessKeyId":"填自己的AccessKeyId",
        "SignatureMethod":"HMAC-SHA1",
        "Timestamp":utc_time,
        "SignatureVersion":"1.0",
        "SignatureNonce":time.time(),
        "RegionId":"cn-hangzhou",
        "AccountName":"阿里云邮件推送的发件人账号",
        "AddressType":1,
        "ReplyToAddress":"true",
        "Subject":"主题",
        "ToAddress":"收件人地址",
        "Action":"SingleSendMail",
        "FromAlias":"发件人名字",
        "TextBody":"发送的邮件内容"
    }

    #对参数进行字典序排序
    parm_tuple = sorted(parm.items(), key=lambda d: d[0], reverse=False)
    CanonicalizedQueryString=parse.urlencode(parm_tuple)
    CanonicalizedQueryString=updateEncode(CanonicalizedQueryString)

    #需要计算签名的文本
    StringToSign="GET&%2F&"+parse.quote(CanonicalizedQueryString)

    #计算签名
    message = StringToSign.encode()
    key = b'testsecret&'
    h = hmac.new(key, message, digestmod='sha1')
    # print(h.digest())
    Signature=base64.b64encode(h.digest()).decode()

    #最终请求地址
    #Signature需要再次编码
    url="https://dm.aliyuncs.com/?Signature="+parse.quote(Signature)+"&"+CanonicalizedQueryString

    statusCode=0
    while(statusCode!=200):
        try:
            ret=request.urlopen(url)
            statusCode=ret.getcode()
            print(statusCode)
        except:
            pass
        time.sleep(5)

sendMail("test subject","test content")

 

posted @ 2021-02-02 16:36  roadwide  阅读(577)  评论(0编辑  收藏  举报