从 Bash shell 脚本发送邮件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1822425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:44:50  来源:igfitidea点击:

Sending mail from a Bash shell script

macosbashemailshell

提问by ridogi

I am writing a Bashshell script for Mac that sends an email notification by opening an automator application that sends email out with the default mail account in Mail.app. The automator application also attaches a text file that the script has written to. The problems with this solution are

我正在为 Mac编写一个Bashshell 脚本,它通过打开一个自动应用程序来发送电子邮件通知,该应用程序使用 Mail.app 中的默认邮件帐户发送电子邮件。自动机应用程序还附加了脚本已写入的文本文件。这个解决方案的问题是

  1. It is visible in the GUI when sending
  2. It steals focus if Mail is not the current application
  3. It is dependent on Mail.app's account setup being valid in the future
  1. 发送时在 GUI 中可见
  2. 如果 Mail 不是当前应用程序,它会窃取焦点
  3. 它取决于Mail.app的帐户设置在将来是否有效

I figure to get around those shortcomings I should send the mail directly from the script by entering SMTPsettings, address to send to, etc. directly in the script. The catch is I would like to deploy this script on multiple computers (10.5 and 10.6) without enabling Postfixon the computer. Is it possible to do this in the script so it will run on a base Mac OS X install of 10.5. and 10.6?

我想为了解决这些缺点,我应该通过直接在脚本中输入SMTP设置、要发送到的地址等直接从脚本发送邮件。问题是我想在多台计算机(10.5 和 10.6)上部署这个脚本而不在计算机上启用Postfix。是否可以在脚本中执行此操作,以便它可以在 10.5 的基本 Mac OS X 安装上运行。和 10.6?

Update: I've found the -bsoption for Sendmail which seems to be what I need, but I'm at a loss of how to specify settings.

更新:我找到了-bsSendmail的选项,这似乎是我需要的,但我不知道如何指定设置。

Also, to clarify, the reason I'd like to specify SMTP settings is that mails from localhost on port 25 sent out via Postfix would be blocked by most corporate firewalls, but if I specify the server and an alternate port I won't run into that problem.

另外,为了澄清,我想指定 SMTP 设置的原因是大多数公司防火墙会阻止来自 localhost 端口 25 上的邮件通过 Postfix 发送,但是如果我指定服务器和备用端口,我将不会运行进入那个问题。

回答by Jason R. Coombs

Since Mac OS X includes Python, consider using a Python script instead of a Bash script. I haven't tested the sending portion, but it follows the standard example.

由于 Mac OS X 包含 Python,请考虑使用 Python 脚本而不是 Bash 脚本。我还没有测试发送部分,但它遵循标准示例

Python script

Python脚本

# Settings

SMTP_SERVER = 'mail.myisp.com'
SMTP_PORT = 25
SMTP_USERNAME = 'myusername'
SMTP_PASSWORD = '$uper$ecret'
SMTP_FROM = '[email protected]'
SMTP_TO = '[email protected]'

TEXT_FILENAME = '/script/output/my_attachment.txt'
MESSAGE = """This is the message
to be sent to the client.
"""

# Now construct the message
import smtplib, email
from email import encoders
import os

msg = email.MIMEMultipart.MIMEMultipart()
body = email.MIMEText.MIMEText(MESSAGE)
attachment = email.MIMEBase.MIMEBase('text', 'plain')
attachment.set_payload(open(TEXT_FILENAME).read())
attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(TEXT_FILENAME))
encoders.encode_base64(attachment)
msg.attach(body)
msg.attach(attachment)
msg.add_header('From', SMTP_FROM)
msg.add_header('To', SMTP_TO)

# Now send the message
mailer = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
# EDIT: mailer is already connected
# mailer.connect()
mailer.login(SMTP_USERNAME, SMTP_PASSWORD)
mailer.sendmail(SMTP_FROM, [SMTP_TO], msg.as_string())
mailer.close()

I hope this helps.

我希望这有帮助。

回答by Brian Postow

Actually, "mail" works just as well.

实际上,“邮件”也同样有效。

mail -s "subject line" [email protected] < filename

works perfectly fine, as long as you have SMTP set up on your machine. I think that most Macs do, by default.

只要您在机器上设置了 SMTP,就可以正常工作。我认为大多数 Mac 都是默认的。

If you don't have SMTP, then the only thing you're going to be able to do is go through Mail.app. An ALTERNATIVE way to go through mail.app is via AppleScript. When you tell Mail.app to send mail via AppleScript you can tell it to not pop up any windows... (this does still require Mail.app to be configured).

如果您没有 SMTP,那么您唯一能做的就是通过 Mail.app。通过 mail.app 的另一种方法是通过AppleScript。当您告诉 Mail.app 通过 AppleScript 发送邮件时,您可以告诉它不要弹出任何窗口......(这仍然需要配置 Mail.app)。

Introduction to Scripting Mailhas a good description of how to work with mail in AppleScript.

Introduction to Scripting Mail很好地描述了如何在 AppleScript 中处理邮件。

回答by Byron Whitlock

There is a program called Sendmail.

有一个程序叫做Sendmail

You probably don't want to use the -bscommand unless you are sending it as raw SMTP like Martin's example. -bsis for running an SMTP server as a deamon. Sendmail will send directly to the receiving mail server (on port 25) unless you override it in the configuration file. You can specify the configuration file by the -Cparamter.

您可能不想使用该-bs命令,除非您像 Martin 的示例一样将其作为原始 SMTP 发送。-bs用于将 SMTP 服务器作为守护进程运行。Sendmail 将直接发送到接收邮件服务器(在端口 25 上),除非您在配置文件中覆盖它。您可以通过-C参数指定配置文件。

In the configuration, you can specify a relay server (any mail server or sendmail running -bson another machine)

在配置中,你可以指定一个中继服务器(任何邮件服务器或-bs在另一台机器上运行的sendmail )

Using a properly configured relay server is good idea because when IT manages mail servers they implement SPFand domain keys. That keeps your mail out of the junk bin.

使用正确配置的中继服务器是个好主意,因为当 IT 管理邮件服务器时,他们会实施SPF域密钥。这使您的邮件远离垃圾箱。

If port 25 is blocked you are left with two options.

如果端口 25 被阻止,您将有两个选择。

  1. Use the corporate SMTP server.
  2. Run sendmail -bdon a machine outside of the corporate firewall that listens on a port other than 25.
  1. 使用公司 SMTP 服务器。
  2. sendmail -bd在公司防火墙之外的机器上运行,该机器侦听 25 以外的端口。

I believe you can add configuration parameters on the command line. What you want is the SMART_HOST option. So call Sendmail like sendmail -OSMART_HOST=nameofhost.com.

我相信你可以在命令行上添加配置参数。你想要的是 SMART_HOST 选项。所以像sendmail -OSMART_HOST=nameofhost.com.

回答by Martin Olsen

Probably the only way you could do this, while keeping the program self-sufficient, is if you have direct access to an SMTP server from the clients.

在保持程序自给自足的同时,您可以做到这一点的唯一方法可能是您可以从客户端直接访问 SMTP 服务器。

If you do have direct access to an SMTP server you can use the SMTP examplefrom wikipedia and turn it into something like this:

如果您确实可以直接访问 SMTP 服务器,则可以使用维基百科中的SMTP 示例并将其转换为以下内容:

#!/bin/bash
telnet smtp.example.org 25 <<_EOF
HELO relay.example.org
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>
DATA
From: Joe <[email protected]>
To: Jane <[email protected]>
Subject: Hello

Hello, world!
.
QUIT
_EOF

To handle errors I would redirect the output from telnet to a file and then grep that for a "success message" later. I am not sure what format the message should be, but I see something like "250 2.0.0 Ok: queued as D86A226C574" in the output from my SMTP server. This would make me grep for "^250.*queued as".

为了处理错误,我会将 telnet 的输出重定向到一个文件,然后 grep 将其用于“成功消息”。我不确定消息应该是什么格式,但我在 SMTP 服务器的输出中看到类似“250 2.0.0 Ok: queued as D86A226C574”的内容。这将使我 grep 为“^250.*queued as”。

回答by Mark Carey

sendEmail is a script that you can use to send email from the command line using more complicated settings, including connecting to a remote smtp server: http://caspian.dotconf.net/menu/Software/SendEmail/

sendEmail 是一个脚本,您可以使用它从命令行使用更复杂的设置发送电子邮件,包括连接到远程 smtp 服务器:http: //caspian.dotconf.net/menu/Software/SendEmail/

On OSX it is easily installable via macports: http://sendemail.darwinports.com/

在 OSX 上,它可以通过 macports 轻松安装:http://sendemail.darwinports.com/

Below is the help page for the command, take note of the -s, -xu, -xp flags:

以下是该命令的帮助页面,请注意 -s、-xu、-xp 标志:

Synopsis:  sendEmail -f ADDRESS [options]

Required:
  -f ADDRESS                from (sender) email address
  * At least one recipient required via -t, -cc, or -bcc
  * Message body required via -m, STDIN, or -o message-file=FILE

Common:
  -t ADDRESS [ADDR ...]     to email address(es)
  -u SUBJECT                message subject
  -m MESSAGE                message body
  -s SERVER[:PORT]          smtp mail relay, default is localhost:25

Optional:
  -a   FILE [FILE ...]      file attachment(s)
  -cc  ADDRESS [ADDR ...]   cc  email address(es)
  -bcc ADDRESS [ADDR ...]   bcc email address(es)

Paranormal:
  -xu USERNAME              authentication user (for SMTP authentication)
  -xp PASSWORD              authentication password (for SMTP authentication)
  -l  LOGFILE               log to the specified file
  -v                        verbosity, use multiple times for greater effect
  -q                        be quiet (no stdout output)
  -o NAME=VALUE             see extended help topic "misc" for details

Help:
  --help TOPIC              The following extended help topics are available:
      addressing            explain addressing and related options
      message               explain message body input and related options
      misc                  explain -xu, -xp, and others
      networking            explain -s, etc
      output                explain logging and other output options

回答by Olivier

Send mail from Bash with one line:

用一行从 Bash 发送邮件:

echo "your mail body" | mail -s "your subject" [email protected] -a "From: [email protected]"

回答by Orwellophile

I whipped this up for the challenge. If you remove the call to 'dig' to obtain the mail relay, it is a 100% native Bash script.

我为这个挑战准备了这个。如果您删除对“dig”的调用以获取邮件中继,则它是 100% 原生 Bash 脚本。

#!/bin/bash
MAIL_FROM="[email protected]"
RCPT_TO="[email protected]"
MESSAGE=message.txt
SMTP_PORT=25
SMTP_DOMAIN=${RCPT_TO##*@}

index=1
while read PRIORITY RELAY
do
    RELAY[$index]=$RELAY
    ((index++))
done < <( dig +short MX $SMTP_DOMAIN )

RELAY_COUNT=${#RELAY[@]}
SMTP_COMMANDS=( "HELO $HOSTNAME" "MAIL FROM: <$MAIL_FROM>" "RCPT TO: <$RCPT_TO>" "DATA" "." "QUIT" )
SMTP_REPLY=([25]=OK [50]=FAIL [51]=FAIL [52]=FAIL [53]=FAIL [54]=FAIL [55]=FAIL [45]=WAIT [35]=DATA [22]=SENT)

for (( i = 1 ; i < RELAY_COUNT ; i++ ))
do
    SMTP_HOST="${RELAY[$i]}"
    echo "Trying relay [$i]: $SMTP_HOST..."
    exec 5<>/dev/tcp/$SMTP_HOST/$SMTP_PORT
    read HELO <&5
    echo GOT: $HELO
    for COMMAND_ORDER in 0 1 2 3 4 5 6 7
    do
            OUT=${SMTP_COMMANDS[COMMAND_ORDER]}
            echo SENDING: $OUT
            echo -e "$OUT\r" >&5

            read -r REPLY <&5
            echo REPLY: $REPLY
            # CODE=($REPLY)
            CODE=${REPLY:0:2}
            ACTION=${SMTP_REPLY[CODE]}
            case $ACTION in
                    WAIT )          echo Temporarily Fail
                                                    break
                                                    ;;
                    FAIL )          echo Failed
                                                    break
                                                    ;;
                    OK )                            ;;
                    SENT )          exit 0
                                                    ;;
                    DATA )          echo Sending Message: $MESSAGE
                                                    cat $MESSAGE >&5
                                                    echo -e "\r" >&5
                                                    ;;
                    * )         echo Unknown SMTP code $CODE
                                                    exit 2
            esac
    done
done

回答by docwhat

Here is a simple Rubyscript to do this. Ruby ships on the Mac OS X versions you mentioned.

这是一个简单的Ruby脚本来执行此操作。Ruby 在您提到的 Mac OS X 版本上发布。

Replace all the bits marked 'replace'. If it fails, it returns a non-zero exit code and a Ruby back trace.

替换所有标记为“替换”的位。如果失败,它将返回一个非零退出代码和一个 Ruby 回溯。

require 'net/smtp'

SMTPHOST = 'replace.yoursmtpserver.example.com'
FROM = '"Your Email" <[email protected]>'

def send(to, subject, message)
  body = <<EOF
From: #{FROM}
To: #{to}
Subject: #{subject}

#{message}
EOF
  Net::SMTP.start(SMTPHOST) do |smtp|
    smtp.send_message body, FROM, to
  end
end

send('[email protected]', 'testing', 'This is a message!')

You can embed this in a Bash script like so:

您可以将其嵌入到 Bash 脚本中,如下所示:

ruby << EOF
 ... script here ...
EOF

For some other ways to send Ruby emails, see Stack Overflow question How do I send mail from a Ruby program?.

有关发送 Ruby 电子邮件的其他一些方法,请参阅 Stack Overflow 问题如何从 Ruby 程序发送邮件?.

You can use other languages that ship with Mac OS X as well:

您也可以使用 Mac OS X 附带的其他语言:

回答by docwhat

1) Why not configure postfixto handle outbound mail only and relay it via a mail gateway? Its biggest advantage is that it is already installed on OS X clients.

1) 为什么不配置postfix为仅处理出站邮件并通过邮件网关中继它?它最大的优点是它已经安装在 OS X 客户端上。

2) Install and configure one of the lightweight MTAs that handle only outbound mail, like nullmaileror ssmtp(available via MacPorts).

2) 安装和配置仅处理出站邮件的轻量级 MTA 之一,例如nullmailerssmtp(可通过 MacPorts 获得)。

In both cases use mailx(1)(or muttif you want to get fancy) to send the mails from a shell script.

在这两种情况下,都使用mailx(1)(或者mutt如果您想花哨的话)从 shell 脚本发送邮件。

There are several questions on Server Fault that go into the details.

关于 Server Fault 有几个问题可以详细介绍。

回答by Alok Singhal

sendmailand even postfixmay be too big to install if all you want to do is to send a few emails from your scripts.

sendmailpostfix如果您只想从脚本中发送几封电子邮件,甚至可能太大而无法安装。

If you have a Gmailaccount for example, you can use Google's servers to send email using SMTP. If you don't want to use gGoogle's server, as long as you have access to some SMTP server, it should work.

例如,如果您有Gmail帐户,则可以使用 Google 的服务器通过SMTP发送电子邮件。如果您不想使用 gGoogle 的服务器,只要您可以访问某个 SMTP 服务器,它应该可以工作。

A very lightweight program that makes it easy to do so is msmtp. They have examples of configuration filesin their documentation.

msmtp是一个非常轻量级的程序,可以很容易地做到这一点。他们的文档中配置文件的示例

The easiest way to do it would be to set up a system-wide default:

最简单的方法是设置系统范围的默认值:

account default
host smtp.gmail.com
from [email protected]
user [email protected]
password XXX
port 587

msmtpshould be very easy to install. In fact, there is a portfor it, so it could be as easy as port install msmtp.

msmtp应该很容易安装。事实上,它有一个端口,所以它可以像port install msmtp.

After installing and configuring msmtp, you can send email to [email protected]using:

安装和配置后msmtp,您可以[email protected]使用以下方式发送电子邮件:

mail -s <subject> [email protected] <<EOF
<mail text, as many lines as you want. Shell variables will be expanded>.
EOF

You can put the above in a script. See man mailfor details.

您可以将上述内容放入脚本中。详情请参阅man mail