通过 SendGrid API 从命令行发送复杂的 html 作为电子邮件正文

Sending a complex html as the body of email from the command line via an SendGrid API

我需要将 HTML 文件作为电子邮件的正文发送给多个客户。我们公司将为此使用 SendGrid,我需要能够通过 API Curl Call 发送电子邮件。

到目前为止,我的做法适用于简单的 html 或纯文本:

curl -s --request POST \
--url https://api.sendgrid.com/v3/mail/send \
--header "Authorization: Bearer SECRET_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"personalizations":[{"to":[{"email":"my1@email.com"},{"email":"my2@email.com"}]}],"from":{"email":"info@somewhere.com"},"subject":"Testing sending emails via SendgridAPI","content":[{"type":"text\/html","value":"Test API Email From ME"}]}'

现在一切正常。问题是当我想用一个相当大、复杂的 HTML 文件的内容替换 'Test API Email From ME' 时。这具有所有常见的 cli 噩梦,例如到处都是 ' 和 " 以及新行。我需要清理 HTML 以完成三件事:

  1. 最终结果需要是有效的命令行字符串

  2. --data 开关参数需要保持有效的 JSON 编码字符串

  3. HTML应该不会断。

我所做的是创建实际的字符串命令并使用脚本语言执行它。因此,在将 html 插入内容字段的值字段之前,我可以在 html 上执行任何我想要的操作。所以我的问题是:我应该对 html 执行哪些字符串操作,以便我可以使用这种方法发送电子邮件?

使用 jq 和 bash

我会用静态数据来做,你可以改进它

  • 为 API 定义一个 JSON 模板:
IFS='' read -r -d '' json_template <<'EOF'
{
  "personalizations": [
    {
      "to": [
        { "email": "my1@email.com" },
        { "email": "my2@email.com" }
      ]
    }
  ],
  "from": { "email": "info@somewhere.com" },
  "subject": "Testing sending emails via SendgridAPI",
  "content": [
    {
      "type": "text/html",
      "value": "Test API Email From ME"
    }
  ]
}
EOF
  • 定义HTML内容:
IFS='' read -r -d '' html_email <<'EOF'
<!doctype html>
<html>
  <head>
    title>Simple Email</title>
  </head>
  <body>
    Test API Email From ME
  </body
</html>
EOF
  • 将JSON中的邮件内容替换为HTML
json_data=$(
    jq -c -n \
        --arg html "$html_email" \
        --argjson template "$json_template" \
        '$template | .content[0].value = $html'
)
  • 发送查询
curl -s --request POST \
    --url https://api.sendgrid.com/v3/mail/send \
    --header "Authorization: Bearer SECRET_API_KEY" \
    --header 'Content-Type: application/json' \
    --data "$json_data"

以下是如何使用 jq 编写适当的 JSON 数据负载,以便将其发送到 API。

jq 将确保每个值、收件人、发件人、主题和 html 正文在提交之前分别编码为适当的 JSON 数据对象、数组和字符串--data @-curl:

我到处都加了注释,所以每一步都做了什么很清楚:

#!/usr/bin/env bash

recipients=(
  'my1@email.com'
  'my2@email.com'
)

from='info@somewhere.com'
subject='Testing sending emails via SendgridAPI'

# Streams null-delimited recipients array entries
printf '%s[=10=]' "${recipients[@]}" |

# jq slurps the null-delimited recipients,
# read the raw html content into the jq $contentHTML variable
# and integrate it all as a proper JSON
jq --slurp --raw-input --rawfile contentHTML example.html \
  --arg from "$from" \
  --arg subject "$subject" \
'
# Fills the jq $recipient JSON array variable
# by splitting the null-delmited entries
# from the incoming stream
split( "\u0000") as $recipients | 

{
  "personalizations": [
    {
      # Uses the $recipients array that has been
      # slurped  from the input stream
      "to": $recipients
    }
  ],
  "from": {

    # Use the $from that has been passed as --arg
    "email": $from
  },

  # Use the $subject that has been passed as --arg
  "subject": $subject,

  "content": [
    {
      "type": "text/html",
      "value": $contentHTML
    }
  ]
}
' |

# Get the resultant JSON piped into curl
# that will read the data from the standard input
# using --data @-
# rather than passing it as an argument, because
# the payload could exceed the maximum length of arguments
curl -s --request POST \
  --url https://api.sendgrid.com/v3/mail/send \
  --header "Authorization: Bearer SECRET_API_KEY" \
  --header 'Content-Type: application/json' \
  --data @-