ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 Linux 命令行将文件作为电子邮件附件发送?

我创建了一个每天晚上在我的 Linux 服务器上运行的脚本,它使用 mysqldump 将我的每个 MySQL 数据库备份到 .sql 文件并将它们打包成一个压缩的 .tar 文件。我想要完成的下一步是通过电子邮件将该 tar 文件发送到远程电子邮件服务器以便妥善保管。我已经能够通过将备份文本文件传送到 mailx 来将正文中的原始脚本发送到电子邮件,如下所示:

$ cat mysqldbbackup.sql | mailx backup@email.example

cat 回显备份文件的文本,该文本通过管道传输到 mailx 程序,收件人的电子邮件地址作为参数传递。

虽然这完成了我的需要,但我认为它可能会更好,有什么方法可以使用 shell 脚本或其他方式将压缩的 .tar 文件作为附件发送到外发电子邮件中?这将比处理包含标题数据并且通常存在自动换行问题等的非常长的电子邮件信息要好得多。

你能分享备份你的 MySQL 数据库的脚本吗?
抱歉,我已经有一段时间没有这样做了。我知道它涉及调用 mysqldump,然后将输出附加到电子邮件(使用 mutt)。我什至可能还有一个步骤将输出压缩为 zip/tar.gz ......
纯粹好奇,为什么要通过电子邮件发送您的备份与 scp 或 rsync ?
猫爸爸 | mailx xxxx@gmail.com 在 python 程序中非常适合我,dados 是一个包含程序结果的文件。我编写了一个函数来捕获程序的结果,“dados”然后 os.system(' cat dados | mailx xxxx@gmail.com') 行已将文件发送到我的电子邮件。完美的!

S
Stephen Ostermiller

没有一个笨蛋对我有用。它认为电子邮件地址是附件的一部分。不得不做:

echo "This is the message body" | mutt -a "/path/to/file.to.attach" -s "subject of message" -- recipient@domain.example

我正在使用 mutt 1.5.21 (2010-09-15),它需要 -a 参数在收件人电子邮件之后
在 openSUSE Leap 42.1 上使用 Mutt 1.5.24 (2015-08-30) 为我工作。
@fugitive 的意思是“选项结束”。看看unix.stackexchange.com/questions/11376/…
有没有办法检查异常并重试发送?
D
Daniel Fone

或者,失败的 mutt:

gzip -c mysqldbbackup.sql | uuencode mysqldbbackup.sql.gz  | mail -s "MySQL DB" backup@email.com

这会将 uuencoded 部分内联而不是作为附件发送。许多邮件客户端虽然认识到这一点,并将 uuencoded 部分显示为附件。
不要在这个时代使用 uuencode。 MIME 稍微复杂一些,但对用户更友好。
@DavidGiven:例如(通过快速浏览)查看此问题的所有其他答案。
他们都不使用邮件!
然后例如 stackoverflow.com/questions/3317174/… 并将 text/html 替换为对您的附件有意义的任何 MIME 类型。 (对于这个具体的例子,我猜是 application/gzip。)
S
Stephen Ostermiller

根据您的 Linux 版本,它可能称为邮件。引用上面的@David:

mail -s "Backup" -a mysqldbbackup.sql backup@email.example < message.txt

或者也:

cat message.txt | mail -s "Backup" -a mysqldbbackup.sql backup@email.example

两种解决方案都不适合我。我收到了 Outlook 2013 的电子邮件,邮件只包含文件名
@nickel715:您系统上的 mail 可能是任何东西的别名吗?
我的手册页显示:-a, --append=HEADER: VALUE append given header to the message being sent
Nathan,您对 David 的引用似乎是错误的 - 他使用的是 mutt 命令,而不是 mail。也正如其他人指出的那样,mutt 现在似乎需要在地址前添加一个 -- 参数。而且我看到 @exhuma 和我实际上同意 mail 中的 -a 选项的作用 - 我在那里困惑了一分钟;)
而不是 -a 你应该使用 -A: -a, --append=HEADER: VALUE append given header to the message being sent -A, --attach=FILE attach FILE
S
Stephen Ostermiller

man mailx 看,mailx 程序没有附加文件的选项。您可以使用其他程序,例如 mutt。

echo "This is the message body" | mutt -a file.to.attach -s "subject of message" recipient@example.com

mutt 的命令行选项可以用 mutt -h 显示。


谢谢!那成功了,我很难让 mutt 默默地做这个动作。
请参阅下面的答案 (stackoverflow.com/a/9524359/10608),因为显然 mutt 的语法已更改,现在需要 --
F
Fredrik Wendt

我使用为此场景创建的 SendEmail。它是为 Ubuntu 打包的,所以我认为它是可用的

sendemail -f sender@some.where -t receiver@some.place -m "这是你的文件!" -a 文件1.jpg 文件2.zip

http://caspian.dotconf.net/menu/Software/SendEmail/


我相信,在您的示例中,它应该是“sendEmail”而不是“sendemail”。
是和否 - 源(里海)使用大写 E,虽然这是命令行工具(在 Unix 世界中)的不常见命名策略,但至少该软件的 Ubuntu 包装在 sendemailsendEmail 3}。
我的 Xubuntu 14.04.3 没有安装 SendEmail
“sudo apt install sendemail” 安装 sendemail 并添加“-f 强制@email.com” 强制 from 字段以使命令正常工作。 sendemail -f mandatory@email.com-t to@some.one -m "Here are your files!" -a file1.jpg file2.zip
可能是 Ubuntu 中最好的选择:不会混淆不同的 mail/mailx/Mail 包,可以附加文件并可以指定自定义发件人地址(而不是丑陋的默认 root@ip.address.or.domain)
佚名

我使用 mpack。

mpack -s subject file user@example.com

不幸的是,mpack 不能将“-”识别为标准输入的别名。但是以下工作,可以很容易地包装在(shell)别名或脚本中:

mpack -s subject /dev/stdin loser@example.com < file

这可以在标准输入的 bash 中工作。我没有 mpack,所以没试过:mpack -s subject /dev/stdin loser@example.com <(stdout_generating_program)
S
Sourabh Potnis
 echo -e 'Hi, \n These are contents of my mail. \n Thanks' | mailx -s 'This is my email subject' -a /path/to/attachment_file.log -b bcc.email@example.com -c cc.email@example.com -r from.email@example.com to.email1@example.com to.email2@example.com to.email3@example.com

这应该是公认的答案。使用默认的 mailx 并完美运行。 Mutt v1.5.21 在使用 cron 时拒绝发送大于 1MB 的附件。
我一直在寻找可以在 EC2 中使用的东西,并且效果很好。
mailx 未正确标准化。任何建议它的答案都应该指出这个警告。至少有三种常用的不兼容变体。
(此外,任何使用 echo -e 的东西都可能不会收到赞成票,尽管我并没有为此感到沮丧而不能反对。)
g
glenn jackman

我曾经在 Solaris 上为 ksh 编写过这个函数(使用 Perl 进行 base64 编码):

# usage: email_attachment to cc subject body attachment_filename
email_attachment() {
    to="$1"
    cc="$2"
    subject="$3"
    body="$4"
    filename="${5:-''}"
    boundary="_====_blah_====_$(date +%Y%m%d%H%M%S)_====_"
    {
        print -- "To: $to"
        print -- "Cc: $cc"
        print -- "Subject: $subject"
        print -- "Content-Type: multipart/mixed; boundary=\"$boundary\""
        print -- "Mime-Version: 1.0"
        print -- ""
        print -- "This is a multi-part message in MIME format."
        print -- ""
        print -- "--$boundary"
        print -- "Content-Type: text/plain; charset=ISO-8859-1"
        print -- ""
        print -- "$body"
        print -- ""
        if [[ -n "$filename" && -f "$filename" && -r "$filename" ]]; then
            print -- "--$boundary"
            print -- "Content-Transfer-Encoding: base64"
            print -- "Content-Type: application/octet-stream; name=$filename"
            print -- "Content-Disposition: attachment; filename=$filename"
            print -- ""
            print -- "$(perl -MMIME::Base64 -e 'open F, shift; @lines=<F>; close F; print MIME::Base64::encode(join(q{}, @lines))' $filename)"
            print -- ""
        fi
        print -- "--${boundary}--"
    } | /usr/lib/sendmail -oi -t
}

在 GNU/Linux 上,可以使用 base64 命令而不是 perl 进行编码
S
Stephen Ostermiller

您可以使用 mutt 发送带有附件的电子邮件

mutt -s "Backup" -a mysqldbbackup.sql backup@example.com < message.txt

至少从 mutt 1.5.21(Ubuntu 可信赖)开始,您需要将 -a 选项放在收件人之后:mutt -s "Backup" backup@email.com -a mysqldbbackup.sql < message.txt,或者在收件人之前使用 -- 选项,如 rynop 的答案所示。
t
tripleee

这里有几个答案建议 mailmailx,因此这更多是帮助您在上下文中解释这些的背景。

历史笔记

Unix mail 的起源可以追溯到贝尔实验室 Unix™(1969 年?)早期历史的迷雾中,我们可能无法希望在这里深入了解它的完整谱系。可以说有许多程序从 mail 继承代码或重新实现(或从重新实现的代码继承)mail,并且没有可以明确标识为“the”mail 的单一代码库。

然而,该职位的竞争者之一肯定是“伯克利邮件”,它最初在 2BSD(1978 年)中被称为 Mail,带有大写 M。但在 3BSD (1979) 中,它也替换了小写的 mail 命令,导致了一些新的混乱。 SVR3 (1986) 包括一个称为 mailx 的导数。大概添加了 x 以使其独特而独特;但这也被复制、重新实现和破坏,因此没有一个单独的版本是确定的。

过去,通过电子邮件发送二进制文件的事实上的标准是 uuencode。它仍然存在,但存在许多可用性问题;如果可能,您应该改为发送 MIME 附件,除非您特别努力能够与 1980 年代后期进行通信。

MIME 于 1990 年代初推出,用于解决电子邮件的几个问题,包括支持单一字符集中纯文本以外的各种类型的内容,该字符集仅适用于英语的一个子集(而且,我们被告知,夏威夷'伊恩)。这引入了对多部分消息、国际化、丰富内容类型等的支持,并在 1990 年代迅速获得了关注。

Heirloom mail/mailx history notes 在撰写本文时最有帮助,如果您喜欢这类东西,当然值得一读。)

当前产品

截至 2018 年,Debian 拥有三个包含 mailmailx 命令的软件包。 (您可以搜索 Provides: mailx。)

debian$ aptitude search ~Pmailx
i   bsd-mailx                       - simple mail user agent
p   heirloom-mailx                  - feature-rich BSD mail(1)
p   mailutils                       - GNU mailutils utilities for handling mail

(我没有将 Debian 单独作为推荐;它是我使用的,所以我很熟悉它;它提供了一种通过引用它们各自的包名称来明确区分各种替代方案的方法。它显然也是来自哪个 Ubuntu 获得这些软件包。)

bsd-mailx 是一个相对简单的 mailx,它似乎不支持发送 MIME 附件。请参阅其手册页并注意这是您希望在默认情况下在 *BSD 系统(包括 MacOS)上找到的那个。

heirloom-mailx 现在被称为 s-nail,并且支持使用 -a 发送 MIME 附件。请参阅其手册页以及更普遍的 Heirloom 项目

mailutils 又名 GNU Mailutils 包含一个 mail/mailx 兼容性包装器,它支持使用 -A 发送 MIME 附件

考虑到这些问题,如果您需要您的代码可移植并且可以依赖于一个有些复杂的包,那么可移植地发送 MIME 附件的简单方法是使用 mutt


我最初将其发布为对一个中等受欢迎的重复问题 stackoverflow.com/questions/902591/… 的回答
S
Stephen Ostermiller

使用 mailx 发送带有一个纯文本附件的纯文本正文电子邮件:

(
  /usr/bin/uuencode attachfile.txt myattachedfilename.txt; 
  /usr/bin/echo "Body of text"
) | mailx -s 'Subject' youremail@example.com

下面是与上面相同的命令,没有换行符

( /usr/bin/uuencode /home/el/attachfile.txt myattachedfilename.txt; /usr/bin/echo "Body of text" ) | mailx -s 'Subject' youremail@example.com

确保您有一个使用以下内容定义的文件 /home/el/attachfile.txt

<html><body>
Government discriminates against programmers with cruel/unusual 35 year prison
sentences for making the world's information free, while bankers that pilfer 
trillions in citizens assets through systematic inflation get the nod and 
walk free among us.
</body></html>

如果您没有 uuencode,请阅读:https://unix.stackexchange.com/questions/16277/how-do-i-get-uuencode-to-work

在 Linux 上,使用 sendmail 发送带有 PDF 附件的 HTML 正文电子邮件:

确保您已安装 ksh:yum info ksh

确保您已安装和配置 sendmail。

确保您已安装并可用 uuencode:https://unix.stackexchange.com/questions/16277/how-do-i-get-uuencode-to-work

创建一个名为 test.sh 的新文件并将其放在您的主目录中:/home/el

将以下代码放入 test.sh

#!/usr/bin/ksh
export MAILFROM="el@defiant.com"
export MAILTO="youremail@example.com"
export SUBJECT="Test PDF for Email"
export BODY="/home/el/email_body.htm"
export ATTACH="/home/el/pdf-test.pdf"
export MAILPART=`uuidgen` ## Generates Unique ID
export MAILPART_BODY=`uuidgen` ## Generates Unique ID

(
 echo "From: $MAILFROM"
 echo "To: $MAILTO"
 echo "Subject: $SUBJECT"
 echo "MIME-Version: 1.0"
 echo "Content-Type: multipart/mixed; boundary=\"$MAILPART\""
 echo ""
 echo "--$MAILPART"
 echo "Content-Type: multipart/alternative; boundary=\"$MAILPART_BODY\""
 echo ""
 echo "--$MAILPART_BODY"
 echo "Content-Type: text/plain; charset=ISO-8859-1"
 echo "You need to enable HTML option for email"
 echo "--$MAILPART_BODY"
 echo "Content-Type: text/html; charset=ISO-8859-1"
 echo "Content-Disposition: inline"
 cat $BODY
 echo "--$MAILPART_BODY--"

 echo "--$MAILPART"
 echo 'Content-Type: application/pdf; name="'$(basename $ATTACH)'"'
 echo "Content-Transfer-Encoding: uuencode"
 echo 'Content-Disposition: attachment; filename="'$(basename $ATTACH)'"'
 echo ""
 uuencode $ATTACH $(basename $ATTACH)
 echo "--$MAILPART--"
) | /usr/sbin/sendmail $MAILTO

更改 test.sh 顶部的导出变量以反映您的地址和文件名。

下载一个测试 pdf 文档并将其放入名为 pdf-test.pdf 的 /home/el

创建一个名为 /home/el/email_body.htm 的文件并将这一行放入其中:

<html><body><b>this is some bold text</b></body></html>

确保 pdf 文件有足够的 755 权限。

运行脚本 ./test.sh

检查您的电子邮件收件箱,文本应为 HTML 格式,并且 pdf 文件会自动解释为二进制文件。请注意不要在一天内使用此功能超过 15 次,即使您将电子邮件发送给自己,gmail 中的垃圾邮件过滤器也会将一个域喷出的电子邮件列入黑名单,而不会让您选择让它们通过。你会发现这不再有效,或者它只允许附件通过,或者电子邮件根本无法通过。如果您必须对此进行大量测试,请将它们分散几天,否则您将被标记为垃圾邮件发送者,此功能将不再起作用。


对我来说,它反过来起作用。 (echo 'Email Body'; uuencode filename filename) | mailx -s 'Subject' user@domain.com
uuencode 不是正确的附件。它只是在其他一些文本的中间嵌入了一个计算机可读的文本块。当没有更好的机制时,它曾经可以正常工作,但那是 20 多年前的事了。
A
Alexander Yancharuk

另一种选择 - Swaks(用于 SMTP 的瑞士军刀)。

swaks -tls \
    --to ${MAIL_TO} \
    --from ${MAIL_FROM} \
    --server ${MAIL_SERVER} \
    --auth LOGIN \
    --auth-user ${MAIL_USER} \
    --auth-password ${MAIL_PASSWORD} \
    --header "Subject: $MAIL_SUBJECT" \
    --header "Content-Type: text/html; charset=UTF-8" \
    --body "$MESSAGE" \
    --attach mysqldbbackup.sql

G
Gunstick

metamail 有 metasend 工具

metasend -f mysqlbackup.sql.gz -t backup@email.com -s Backup -m application/x-gzip -b

这过去几乎无处不在,但几乎从未使用过。因为它长时间无人维护(并且仍然是 AFAIK),它已从许多平台上的事实上的标准工具集中删除。
r
rumpel

Mailutils 让这变得小菜一碟

echo "Body" | mail.mailutils -M -s "My Subject" -A attachment.pdf mail@example.org

-A 文件附加文件

-M 启用 MIME,以便您可以拥有附件和明文正文。

如果尚未安装,请运行

sudo apt install mailutils

t
the Tin Man

我通常只在 RHEL 上使用 mail 命令。我已经尝试过mailx,它非常有效。

mailx -s "Sending Files" -a First_LocalConfig.conf -a
Second_LocalConfig.conf Recipient@myemail.com

This is the content of my msg.

.

p
poncho

我用了

echo "Start of Body" && uuencode log.cfg readme.txt | mail -s "subject" "a@b.c" 

这对我很有效....


echo 在这里没用;它会将文本输出到终端,而不是输出到 mail 的管道。与此处的其他类似答案一样,uuencode 不是“附件”,尽管某些电子邮件客户端会帮助隐藏丑陋,因此如果您不仔细看,它似乎是一个。
K
Konchog

从源机器

mysqldump --defaults-extra-file=sql.cnf database | gzip | base64 | mail me@myemail.com

在目标机器上。将收到的邮件正文保存为db.sql.gz.b64;然后..

base64 -D -i db.sql.gz.b64 | gzip -d | mysql --defaults-extra-file=sql.cnf

这样可以获取数据,但缺少 MIME 标头来告诉用户如何处理它。除非他们知道它是什么,否则他们可能无法弄清楚如何使用它。正确的 MIME 结构至少会将 base64 数据显示为附件,而不是实际的消息文本。
你把我带到了@tripleee - 我并没有真正考虑为第三方使用这种机制。我认识的大多数人都不知道如何处理它,即使他们确实有 Mime 标题来帮助他们。
S
Stephen Ostermiller

使用 mailx 命令

 echo "Message Body Here" | mailx -s "Subject Here" -a file_name user@example.com

使用发送邮件

#!/bin/ksh

fileToAttach=data.txt

`(echo "To: user@company.example"
  echo "Cc: user@company.example"
  echo "From: Application"
  echo "Subject: your subject"
  echo  your body
  uuencode $fileToAttach $fileToAttach
  )| eval /usr/sbin/sendmail -t `;

sendmail 是一个很好的例子,很高兴我在这里找到了它。
请注意,您需要在“您的正文”开头有一个空行,否则正文将消失在标题中,或者可能完全破坏消息。另请参阅其他地方关于避免使用 uuencode 以支持 MIME 的说明。
可怕的 eval 和整个装置周围的神秘反引号在这里完全没有必要。
M
Mike Graf

只是为了增加我的 2 美分,我会编写自己的 PHP 脚本:

http://php.net/manual/en/function.mail.php

该页面上的示例中有很多方法可以制作附件。


并非每台服务器都安装了 PHP。如果您真的想走“编写自己的脚本”的道路,那么 perl 或 python 更适合,因为它们通常默认可用。
sh 更为普遍。有重复的问题,有很好的例子的答案; here is mine.
s
sth

mailx 现在确实有一个用于附件的 -a 选项。


“-a”选项用于标题
man mail[x],10/9/10 的 12.5 版(几年前)清楚地说 -a file 将给定的文件附加到消息中。`
一些 版本的mailx 可以。我相信有两种实现方式。一个 -a 用于附件,另一个用于标题。
Ubuntu 中的 mailx 版本来自 GNU,其中 -a 表示添加标头。 manpages.ubuntu.com/manpages/lucid/en/man1/mailx.1.html 哪个系统和哪个 mailx 做附件?
在新实现中,“-a”用于标题,“-A”用于附件
t
the Tin Man

不是一种发送电子邮件的方法,但您可以使用在线 Git 服务器(例如 Bitbucket 或类似服务)。

这样,您可以使用 git push 命令,所有版本都将以压缩和有组织的方式存储。


P
Pipo

对我来说最短的方法是

file=filename_or_filepath;uuencode $file $file|mail -s "optional subject" email_address

所以对于你的例子,它将是

file=your_sql.log;gzip -c $file;uuencode ${file}.gz ${file}|mail -s "file with magnets" ph.gachoud@gmail.com

好的部分是我可以用 Ctrl+r 调用它来发送另一个文件......


大括号对您没有多大好处,但要完全可移植,您应该在变量周围使用双引号。另请参阅stackoverflow.com/questions/10067266/…
n
nurp

如果文件是文本,您可以在正文中将其最简单地发送为:

sendmail recipient@example.com < message.txt

这不会将其作为附件发送,甚至不会作为邮件正文发送。 Sendmail 期望它的输入是完整的、格式正确的 RFC5322 电子邮件,如果不是这样,它可能会以有趣的方式失败。
d
dagorv

这就是我在 CentOS 中处理一个大型日志文件的方式:

#!/bin/sh
MAIL_CMD="$(which mail)"
WHOAMI="$(whoami)"
HOSTNAME="$(hostname)"
EMAIL"your@email.address"
LOGDIR="/var/log/aide"
LOGNAME="$(basename "$0")_$(date "+%Y%m%d_%H%M")"

if cd ${LOGDIR}; then
  /bin/tar -zcvf "${LOGDIR}/${LOGNAME}".tgz "${LOGDIR}/${LOGNAME}.log" > /dev/null 2>&1
  if [ -n "${MAIL_CMD}" ]; then
  # This works too. The message content will be taken from text file below
  # echo 'Hello!' >/root/scripts/audit_check.sh.txt
  # echo "Attachment" | ${MAIL_CMD} -s "${HOSTNAME} Aide report" -q /root/scripts/audit_check.sh.txt -a ${LOGNAME}.tgz -S from=${WHOAMI}@${HOSTNAME} ${EMAIL}
    echo "Attachment" | ${MAIL_CMD} -s "${HOSTNAME} Aide report" -a "${LOGNAME}.tgz" -S from="${WHOAMI}@${HOSTNAME}" "${EMAIL}"
    /bin/rm "${LOGDIR}/${LOGNAME}.log"
  fi
fi

为什么要定义 WHOAMIHOSTNAME 两次?
这有几个 shell 编码风格错误。 shellcheck.net 会指出其中的一些,但不是全部。
P
Paras Singh

如果 mutt 不工作或没有安装,试试这个 -

*#!/bin/sh

FilePath=$1
FileName=$2
Message=$3
MailList=$4

cd $FilePath

Rec_count=$(wc -l < $FileName)
if [ $Rec_count -gt 0 ]
then
(echo "The attachment contains $Message" ; uuencode $FileName $FileName.csv ) | mailx -s "$Message" $MailList
fi*

这有许多编码错误,这将使它看起来与琐碎的示例一起工作,但在现实生活中会中断。有关一些建议,请参阅 shellcheck.net,但它不会告诉您避免uuencode