简体   繁体   English

curl:发送带有嵌入图像和附件的 html email

[英]curl : send html email with embedded image and attachment

My goal is to send an email using curl with an html body with embedded image such as:我的目标是使用curl和带有嵌入图像的 html 主体发送 email,例如:

电子邮件模板图像

I'm sending the email like this:我像这样发送 email:

curl "smtp://smtp.gmail.com:587" -v \
     --mail-from "sender@gmail.com" \
     --mail-rcpt "receiver@gmail.com" \
     --ssl -u sender@gmail.com:secretpassword \
     -T "message.txt" -k --anyauth

My message.txt looks like:我的message.txt看起来像:

From: Some Name <sender@gmail.com>
To: Some Name <receiver@gmail.com>
Subject: example of mail
Reply-To: Some Name <sender@gmail.com>
Cc: 
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="MULTIPART-MIXED-BOUNDARY"

--MULTIPART-MIXED-BOUNDARY
Content-Type: multipart/alternative; boundary="MULTIPART-ALTERNATIVE-BOUNDARY"

--MULTIPART-ALTERNATIVE-BOUNDARY
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
Content-Disposition: inline

PGh0bWw+Cjxib2R5PgogICAgPGRpdj4KICAgICAgICA8cD5IZWxsbywgPC9wPgogICAgICAgIDxw
PlBsZWFzZSBzZWUgdGhlIGxvZyBmaWxlIGF0dGFjaGVkPC9wPgogICAgICAgIDxwPkFkbWluIFRl
YW08L3A+CiAgICAgICAgPGltZyBzcmM9ImFkbWluLnBuZyIgd2lkdGg9IjE1MCIgaGVpZ2h0PSI1
MCI+CiAgICA8L2Rpdj4KPC9ib2R5Pgo8L2h0bWw+Cg==
--MULTIPART-ALTERNATIVE-BOUNDARY--
--MULTIPART-MIXED-BOUNDARY

The html decoded is:解码后的 html 为:

<html>
<body>
    <div>
        <p>Hello, </p>
        <p>Please see the log file attached</p>
        <p>Admin Team</p>
        <img src="admin.png" width="150" height="50">
    </div>
</body>
</html>

How can I embed admin.png in this html and attach another file log.txt to this email using curl and bash ? How can I embed admin.png in this html and attach another file log.txt to this email using curl and bash ?

The solution I came up with is to base64 encode all the attachment (image and text file) and to include them into the uploaded file directly in the multipart/mixed body such as :我想出的解决方案是对所有附件(图像和文本文件)进行 base64 编码,并将它们直接包含在multipart/mixed正文中的上传文件中,例如:

--MULTIPART-MIXED-BOUNDARY
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-Disposition: inline
Content-Id: <admin.png>
iVBORw0KGgoAAAANSUhEUgAAAIAAAACgCAIAAABL8POqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
B3RJTUUH4AQNDwEVouBdqAAAG2xJREFUeNrtfX9oHFe25jdDBU5BG25BG7pABhXEkDJjSIsYIs1m
WbfJA8ubhcjjgdiTQNJOYCInj0RKYGIl8CbyPF4iZSCxEkgsB5LIgWQlL2Pcfow3bdgw0mMzox6e
....


--MULTIPART-MIXED-BOUNDARY
Content-Type: text/plain
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename=log.txt
c29tZSBsb2cgaW4gYSB0eHQgZmlsZSB0byBhdHRhY2ggdG8gdGhlIG1haWwK


--MULTIPART-MIXED-BOUNDARY--

The Content-Id header is used to identify the resource that can be referenced in the html with : cid: like : Content-Id标头用于标识可以在 html 中引用的资源: cid: like:

<img src="cid:admin.png" width="150" height="50">

Here is a complete bash example to send an html email with and admin.png embedded image and a log.txt attached to it :这是一个完整的bash示例,用于发送带有admin.png嵌入图像和log.txt的 html 电子邮件:

#!/bin/bash

rtmp_url="smtp://smtp.gmail.com:587"
rtmp_from="sender@gmail.com"
rtmp_to="receiver@gmail.com"
rtmp_credentials="sender@gmail.com:secretpassword"

file_upload="data.txt"

# html message to send
echo "<html>
<body>
    <div>
        <p>Hello, </p>
        <p>Please see the log file attached</p>
        <p>Admin Team</p>
        <img src=\"cid:admin.png\" width=\"150\" height=\"50\">
    </div>
</body>
</html>" > message.html

# log.txt file to attached to the mail
echo "some log in a txt file to attach to the mail" > log.txt

mail_from="Some Name <$rtmp_from>"
mail_to="Some Name <$rtmp_to>"
mail_subject="example of mail"
mail_reply_to="Some Name <$rtmp_from>"
mail_cc=""

# add an image to data.txt : 
# $1 : type (ex : image/png)
# $2 : image content id filename (match the cid:filename.png in html document)
# $3 : image content base64 encoded
# $4 : filename for the attached file if content id filename empty
function add_file {
    echo "--MULTIPART-MIXED-BOUNDARY
Content-Type: $1
Content-Transfer-Encoding: base64" >> "$file_upload"

    if [ ! -z "$2" ]; then
        echo "Content-Disposition: inline
Content-Id: <$2>" >> "$file_upload"
    else
        echo "Content-Disposition: attachment; filename=$4" >> "$file_upload"
    fi
    echo "$3

" >> "$file_upload"
}

message_base64=$(cat message.html | base64)

echo "From: $mail_from
To: $mail_to
Subject: $mail_subject
Reply-To: $mail_reply_to
Cc: $mail_cc
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=\"MULTIPART-MIXED-BOUNDARY\"

--MULTIPART-MIXED-BOUNDARY
Content-Type: multipart/alternative; boundary=\"MULTIPART-ALTERNATIVE-BOUNDARY\"

--MULTIPART-ALTERNATIVE-BOUNDARY
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
Content-Disposition: inline

$message_base64
--MULTIPART-ALTERNATIVE-BOUNDARY--" > "$file_upload"

# add an image with corresponding content-id (here admin.png)
image_base64=$(curl -s "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png" | base64)
add_file "image/png" "admin.png" "$image_base64"

# add the log file
log_file=$(cat log.txt | base64)
add_file "text/plain" "" "$log_file" "log.txt"

# add another image 
#image_base64=$(curl -s "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png" | base64)
#add_file "image/png" "something.png" "$image_base64"

# end of uploaded file
echo "--MULTIPART-MIXED-BOUNDARY--" >> "$file_upload"

# send email
echo "sending ...."
curl -s "$rtmp_url" \
     --mail-from "$rtmp_from" \
     --mail-rcpt "$rtmp_to" \
     --ssl -u "$rtmp_credentials" \
     -T "$file_upload" -k --anyauth
res=$?
if test "$res" != "0"; then
   echo "sending failed with: $res"
else
    echo "OK"
fi

really want to follow up on your old post Scrap articles form wsj by requests, CURL and BeautifulSoup . 我真的很想通过请求,CURL和BeautifulSoup来跟踪您以前的旧报废表单wsj中的文章 is it possible to ask you to update the answer? 是否可以要求您更新答案? really appreciate it. 非常感谢。 has been working on it for many hours but could not figure out how to do it. 已经研究了许多小时,但无法弄清楚该怎么做。

Plus one, your code example is a bit misleading tough, in fact it doesn't work.另外,您的代码示例有点误导性强,实际上它不起作用。 As you say, you just have to enclose each part in a boundary, in your case the delimiter is:正如您所说,您只需将每个部分括在一个边界中,在您的情况下,分隔符是:

"--MULTIPART-MIXED-BOUNDARY". “--MULTIPART-MIXED-BOUNDARY”。

Nonetheless it could be any other user defined string.尽管如此,它可以是任何其他用户定义的字符串。 You are nesting multiple boundary types, which isn't necessary.您正在嵌套多个边界类型,这是不必要的。 HTML content doesn't need to be base64 encoded, it can go encoded if you will though. HTML 内容不需要是 base64 编码的,如果你愿意,它可以被编码。

You need a blank line after and before each delimiter.每个分隔符前后都需要一个空行。

I recommend taking a look at the W3 papers and examples: https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html我建议查看 W3 论文和示例: https : //www.w3.org/Protocols/rfc1341/7_2_Multipart.html

Here's a shell script you could use.这是您可以使用的 shell 脚本。 I heavily derived from https://blog.ambor.com/2021/08/using-curl-to-send-e-mail-with.html我大量来自https://blog.ambor.com/2021/08/using-curl-to-send-e-mail-with.html

Passwords could be stored in a .netrc file as discussed on: https://everything.curl.dev/usingcurl/netrc but I haven't tried that.密码可以存储在 .netrc 文件中,如下所述: https ://everything.curl.dev/usingcurl/netrc 但我没有尝试过。

Just make sure the image you need is embedded in the HTML using base64 encoding.只需确保您需要的图像使用 base64 编码嵌入到 HTML 中。

#!/bin/bash

declare -a VOPTS;
declare -a HOPTS;

sesAccess="sender.account.authentication@email.id" ;
sesSecret="sender.account.passwordXXXXXX";
sesFromName="Sender Full Name";
sesFromAddress='<sender@email.id>';
sesToName="Recipient Full Name";
sesToAddress="<recepient@email.id>"
sesSubject="Email Subject Line";
sesSMTP='mail.server.fqdn';
sesPort='465';
sesMessage=$'Test of line 1\nTest of line 2'
sesFile="$1"; # attachment is first argument
sesHTMLbody="/path/to/html/file.html"; # content of this file will be used to create HTML body

sesMIMEType=`file --mime-type "$sesFile" | sed 's/.*: //'`;
# sesMIMEType=`file -b --mime-type "$sesFile"`;

VOPTS=();
HOPTS=();

#Curl Options
VOPTS+=("-v");
VOPTS+=("--url"); VOPTS+=("smtps://$sesSMTP:$sesPort"); 
VOPTS+=("--ssl-reqd")
VOPTS+=("--user"); VOPTS+=("${sesAccess}:${sesSecret}"); 
VOPTS+=("--mail-from"); VOPTS+=("${sesFromAddress}");
VOPTS+=("--mail-rcpt"); VOPTS+=("${sesToAddress}");

#Header Options
HOPTS+=("-H"); HOPTS+=("Subject: ${sesSubject}");
HOPTS+=("-H"); HOPTS+=("From: ${sesFromName} ${sesFromAddress}"); 
HOPTS+=("-H"); HOPTS+=("To: ${sesToName} ${sesToAddress}"); 

curl "${VOPTS[@]}" -F '=(;type=multipart/mixed' -F "=<$sesHTMLbody;type=text/html;encoder=base64" -F "file=@$sesFile;type=$sesMIMEType;encoder=base64" -F '=)' "${HOPTS[@]}"

exit

The answer by @bertrand-martel was mostly right on my system running Ubuntu 22.04 and submitting to a postfix server in my network. @bertrand-martel 的答案在我运行 Ubuntu 22.04 并提交到我网络中的后缀服务器的系统上大部分是正确的。 The html email message came through just fine, and I had empty attachments named correctly. html email 消息通过就好了,我有正确命名的空附件。 I had to edit the add_file function he defined and add in a blank line before the $3 at the very end.我必须编辑他定义的 add_file function 并在最后的 $3 之前添加一个空行。 The email would not work without a blank line between the Content-Disposition: and the base64 encoding.如果 Content-Disposition: 和 base64 编码之间没有空行,email 将无法工作。 I also had to insert a blank line after the --MULTIPART-ALTERNATIVE-BOUNDARY--.我还必须在 --MULTIPART-ALTERNATIVE-BOUNDARY-- 之后插入一个空行。 Once I made those changes, the html message, the embedded image, and the attached file all came across correctly.一旦我进行了这些更改,html 消息、嵌入的图像和附件都正确出现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM