Current section

Files

Jump to
aliyun_api lib aliyun_api email cli.ex
Raw

lib/aliyun_api/email/cli.ex

defmodule AliyunAPI.Email do
import AliyunAPI, only: [url_encode: 1]
@doc """
发送邮件
doc:https://help.aliyun.com/document_detail/29444.html
## opts
* `:app` 必须
* `:to_address` 必须
* `:from_alias` 必须
* `:subject` 必须
* `:html_body`
* `:text_body`
* `:click_trace` true/false
## Examples
```
## 发送纯文本
AliyunAPI.Email.send(
app: :worth,
to_address: "andywang9527@qq.com",
subject: "Hello Test from aliyun util",
text_body: "Hello Worth"
)
## 发送富文本
AliyunAPI.Email.send(
app: :worth,
to_address: "andywang9527@qq.com",
subject: "Hello Test from aliyun util",
html_body: "<h1>Hello Worth</h1><div style=\"color: red;\">hello world</div>"
)
```
## Return
```
## 发送成功
{:ok,
%{EnvId: "58678883849", RequestId: "AE53BE89-065F-4564-B13D-958D43FF5503"}}
## 发送失败, 地址格式错误
{:error, 400,
%{
body: "{\"RequestId\":\"3067F00C-F357-415D-B17F-84F559E37CF5\",\"HostId\":\"dm.aliyuncs.com\",\"Code\":\"InvalidToAddress\",\"Message\":\"The specified toAddress is wrongly formed.\"}",
error: %{
Code: "InvalidToAddress",
HostId: "dm.aliyuncs.com",
Message: "The specified toAddress is wrongly formed.",
RequestId: "3067F00C-F357-415D-B17F-84F559E37CF5"
},
headers: [
{"Date", "Sun, 17 Feb 2019 09:00:44 GMT"},
{"Content-Type", "application/json; charset=UTF-8"},
{"Content-Length", "160"},
{"Connection", "close"},
{"Access-Control-Allow-Origin", "*"},
{"Access-Control-Allow-Methods", "POST, GET, OPTIONS"},
{"Access-Control-Allow-Headers",
"X-Requested-With, X-Sequence, _aop_secret, _aop_signature"},
{"Access-Control-Max-Age", "172800"},
{"Server", "Jetty(7.2.2.v20101205)"}
]
}}
## 发送失败,其他错误
{:error, :nxdomain}
```
"""
def send(opts \\ []) do
email_opts = AliyunAPI.Env.email_opts(opts[:app])
if email_opts do
url = "https://#{AliyunAPI.Env.email_endpoint(opts[:app])}"
click_trace = if opts[:click_trace] == false, do: "0", else: "1"
params =
"SingleSendMail"
|> _format_arguments(opts[:app])
|> Map.merge(%{
"AccountName" => email_opts[:from_address],
"ReplyToAddress" => true,
"AddressType" => 1,
"ToAddress" => opts[:to_address],
"FromAlias" => opts[:from_alias] || email_opts[:from_alias],
"Subject" => opts[:subject],
"ClickTrace" => click_trace,
"HtmlBody" => opts[:html_body],
"TextBody" => opts[:text_body]
})
|> _normalize_params(opts[:app], "GET")
AliyunAPI.http_request(url <> "?" <> URI.encode_query(params), :get)
|> case do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, Jason.decode!(body, keys: :atoms)}
{:ok, %HTTPoison.Response{status_code: status_code, headers: headers, body: body}} ->
error = Jason.decode!(body, keys: :atoms)
{:error, status_code, %{body: body, headers: headers, error: error}}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
else
{:error, :missing_config}
end
end
defp _normalize_params(arguments, app, http_method) do
arguments = arguments |> AliyunAPI.filter_params()
signature = arguments |> _get_signature(app, http_method)
arguments |> Map.put("Signature", signature)
end
defp _get_signature(arguments, app, method) do
args =
arguments
|> Enum.sort_by(fn {key, _} -> key end)
|> Enum.map(fn {key, val} -> {url_encode(key), url_encode(val)} end)
|> Enum.map(fn {key, val} -> "#{key}=#{val}" end)
|> Enum.join("&")
string_to_sign =
"#{String.upcase(method)}" <> "&" <> url_encode("/") <> "&" <> url_encode(args)
:sha
|> :crypto.hmac("#{AliyunAPI.Env.email_access_key_secret(app)}&", string_to_sign)
|> Base.encode64()
end
defp _format_arguments(action, app) do
%{
"Format" => "JSON",
"Version" => "2015-11-23",
"SignatureMethod" => "HMAC-SHA1",
"SignatureNonce" => AliyunAPI.SecureRandom.uuid(),
"SignatureVersion" => "1.0",
"Action" => action,
"AccessKeyId" => AliyunAPI.Env.email_access_key_id(app),
"Timestamp" => Timex.format!(Timex.now(), "%Y-%m-%dT%H:%M:%SZ", :strftime)
}
end
end