从Bash shell脚本发送邮件

时间:2009-11-30 21:12:43

标签: macos bash email shell

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

  1. 发送时在GUI中可见
  2. 如果Mail不是当前的应用程序,它会窃取焦点
  3. 这取决于Mail.app的帐户设置在将来有效
  4. 我想通过直接在脚本中输入SMTP设置,发送地址等来直接从脚本发送邮件来解决这些缺点。问题是我想在多台计算机(10.5和10.6)上部署此脚本而不在计算机上启用Postfix。是否可以在脚本中执行此操作,以便它将在10.5的基本Mac OS X安装上运行。和10.6?

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

    此外,澄清一下,我想指定SMTP设置的原因是,通过Postfix发送的端口25上的localhost邮件将被大多数企业防火墙阻止,但如果我指定服务器和备用端口我赢了遇到这个问题。

12 个答案:

答案 0 :(得分:52)

由于Mac OS X包含Python,因此请考虑使用Python脚本而不是Bash脚本。我没有测试发送部分,但它遵循standard example

Python脚本

# Settings

SMTP_SERVER = 'mail.myisp.com'
SMTP_PORT = 25
SMTP_USERNAME = 'myusername'
SMTP_PASSWORD = '$uper$ecret'
SMTP_FROM = 'sender@example.com'
SMTP_TO = 'recipient@example.com'

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()

我希望这会有所帮助。

答案 1 :(得分:37)

实际上,“邮件”的效果也一样。

mail -s "subject line" name@address.ext < filename
只要您在计算机上设置了SMTP,

就可以正常工作。我认为大多数Mac都是默认的。

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

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

答案 2 :(得分:15)

有一个名为Sendmail的程序。

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

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

使用正确配置的中继服务器是个好主意,因为当IT管理邮件服务器时,他们会实施SPFdomain keys。这可以让你的邮件远离垃圾箱。

如果端口25被阻止,则剩下两个选项。

  1. 使用公司SMTP服务器。
  2. 在外面的机器上运行sendmail -bd 听取的企业防火墙 在25以外的港口。
  3. 我相信您可以在命令行中添加配置参数。你想要的是SMART_HOST选项。所以请像sendmail -OSMART_HOST=nameofhost.com一样调用Sendmail。

答案 3 :(得分:10)

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

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

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

Hello, world!
.
QUIT
_EOF

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

答案 4 :(得分:6)

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

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

以下是该命令的帮助页面,请注意-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

答案 5 :(得分:5)

用一行发送来自Bash的邮件:

echo "your mail body" | mail -s "your subject" yourmail@yourdomain.com -a "From: sender@senderdomain.com"

答案 6 :(得分:4)

这是一个简单的Ruby脚本来执行此操作。 Ruby提供了你提到的Mac OS X版本。

替换所有标记为'replace'的位。如果失败,则返回非零退出代码和Ruby返回跟踪。

require 'net/smtp'

SMTPHOST = 'replace.yoursmtpserver.example.com'
FROM = '"Your Email" <youremail@replace.example.com>'

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('someemail@replace.example.com', 'testing', 'This is a message!')

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

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

有关发送Ruby电子邮件的其他一些方法,请参阅Stack Overflow问题 How do I send mail from a Ruby program?

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

答案 7 :(得分:4)

我为挑战而鞭打了这个。如果您删除“dig”调用以获取邮件中继,则它是100%本机Bash脚本。

#!/bin/bash
MAIL_FROM="sfinktah@bash.spamtrak.org"
RCPT_TO="sfinktah@bash.spamtrak.org"
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

答案 8 :(得分:3)

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

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

在这两种情况下,使用mailx(1)(或mutt,如果你想获得幻想)从shell脚本发送邮件。

有关服务器故障的几个问题,请参阅详细信息。

答案 9 :(得分:3)

sendmail甚至postfix可能太大而无法安装,如果你想要做的就是从你的脚本发送一些电子邮件。

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

一个非常轻量级的程序,可以很容易地执行此操作msmtp。他们的examples of configuration files中有documentation

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

account default
host smtp.gmail.com
from john.doe@gmail.com
user john.doe@gmail.com
password XXX
port 587

msmtp应该非常容易安装。事实上,它有a port,所以它可以像port install msmtp一样简单。

安装和配置msmtp后,您可以使用以下方式向john.doe@gmail.com发送电子邮件:

mail -s <subject> john.doe@gmail.com <<EOF
<mail text, as many lines as you want. Shell variables will be expanded>.
EOF

您可以将上述内容放入脚本中。有关详细信息,请参阅man mail

答案 10 :(得分:0)

这是我在各种UNIX系统上使用的修改过的shell脚本片段...... (echo "${MESSAGE}" | ${uuencode} ${ATTACHMENT} $ basename $ {ATTACHMENT} ) | ${mailx} -s "${SUBJECT}" "${TO_LIST}"

uuencode和mailx设置为可执行文件。其他变量来自使用getopts解析的用户输入。

这确实有效但我不得不承认我使用简单的Java程序来发送控制台电子邮件。

答案 11 :(得分:0)

尝试使用mtcmail。它是一个相当完整的电子邮件发件人,完全独立。