Отправка почты из сценария оболочки Bash - PullRequest
35 голосов
/ 01 декабря 2009

Я пишу сценарий оболочки Bash для Mac, который отправляет уведомление по электронной почте, открывая приложение автоматизатора, которое отправляет электронную почту с учетной записью по умолчанию в Mail.app. Приложение automator также прикрепляет текстовый файл, в который записан скрипт. Проблемы с этим решением

  1. Видно в графическом интерфейсе при отправке
  2. Он крадет фокус, если Почта не является текущим приложением
  3. Это зависит от настроек учетной записи Mail.app, которые будут действительны в будущем

Я решил обойти эти недостатки. Я должен отправить письмо прямо из скрипта, введя SMTP настройки, адрес для отправки и т. Д. Прямо в скрипте. Подвох в том, что я хотел бы развернуть этот сценарий на нескольких компьютерах (10.5 и 10.6) без включения Postfix на компьютере. Возможно ли сделать это в скрипте, чтобы он работал на базовой Mac OS X с установкой 10.5. и 10,6?

Обновление: я нашел опцию -bs для Sendmail, которая, кажется, мне нужна, но я не знаю, как задать настройки.

Также, чтобы уточнить, причина, по которой я хотел бы указать настройки SMTP, заключается в том, что сообщения с локального хоста на порту 25, отправленные через Postfix, будут блокироваться большинством корпоративных брандмауэров, но если я укажу сервер и альтернативный порт, я выиграю не сталкивайтесь с этой проблемой.

Ответы [ 12 ]

52 голосов
/ 21 декабря 2009

Поскольку Mac OS X включает в себя Python, рассмотрите возможность использования сценария Python вместо сценария Bash. Я не проверял часть отправки, но она соответствует стандартному примеру 1002 *.

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

Надеюсь, это поможет.

37 голосов
/ 21 декабря 2009

На самом деле, «почта» работает так же хорошо.

mail -s "subject line" name@address.ext < filename

работает отлично, если на вашем компьютере настроен SMTP. Я думаю, что большинство компьютеров Mac по умолчанию.

Если у вас нет SMTP, то единственное, что вы сможете сделать, - это пройти через Mail.app. АЛЬТЕРНАТИВНЫЙ способ пройти через mail.app - через AppleScript . Когда вы указываете Mail.app отправлять почту через AppleScript, вы можете указать, чтобы он не отображал окна ... (для этого все же требуется настроить Mail.app).

Введение в создание сценариев почты содержит хорошее описание работы с почтой в AppleScript.

15 голосов
/ 01 декабря 2009

Существует программа под названием Sendmail .

Вы, вероятно, не захотите использовать команду -bs, если не отправляете ее в виде необработанного SMTP, как пример Мартина. -bs предназначен для запуска SMTP-сервера в качестве демона. Sendmail будет отправлять напрямую на принимающий почтовый сервер (через порт 25), если вы не переопределите его в файле конфигурации. Вы можете указать файл конфигурации с помощью параметра -C.

В конфигурации вы можете указать сервер ретрансляции (любой почтовый сервер или sendmail, работающий -bs на другом компьютере)

Использование правильно настроенного сервера ретрансляции - хорошая идея, потому что когда ИТ-специалисты управляют почтовыми серверами, они реализуют SPF и ключи домена . Это удерживает вашу почту от мусорной корзины.

Если порт 25 заблокирован, у вас остается две опции.

  1. Использовать корпоративный SMTP-сервер.
  2. Запуск sendmail -bd на машине вне корпоративный брандмауэр, который слушает в порту, отличном от 25.

Полагаю, вы можете добавить параметры конфигурации в командной строке. То, что вы хотите, это опция SMART_HOST. Так что звоните Sendmail как sendmail -OSMART_HOST=nameofhost.com.

10 голосов
/ 21 декабря 2009

Вероятно, единственный способ сделать это, сохраняя самодостаточность программы, - это иметь прямой доступ к SMTP-серверу от клиентов.

Если у вас есть прямой доступ к SMTP-серверу, вы можете использовать SMTP-пример из википедии и превратить его в нечто вроде этого:

#!/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 для сообщения об успехе. Я не уверен, в каком формате должно быть сообщение, но я вижу что-то вроде «250 2.0.0 Ok: поставлен в очередь как D86A226C574» в выводе с моего SMTP-сервера. Это сделало бы меня grep для "^ 250. * в очереди как".

6 голосов
/ 22 декабря 2009

sendEmail - это скрипт, который вы можете использовать для отправки электронной почты из командной строки с использованием более сложных настроек, включая подключение к удаленному серверу SMTP: http://caspian.dotconf.net/menu/Software/SendEmail/

В OSX его легко установить через macports: 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 голосов
/ 11 декабря 2012

Отправка почты из Bash одной строкой:

echo "your mail body" | mail -s "your subject" yourmail@yourdomain.com -a "From: sender@senderdomain.com"
4 голосов
/ 23 февраля 2012

Я поднял это для вызова. Если вы удалите вызов «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
4 голосов
/ 21 декабря 2009

Вот простой Ruby скрипт для этого. Ruby поставляется с упомянутыми вами версиями Mac OS X.

Заменить все биты, помеченные как «заменить». Если происходит сбой, он возвращает ненулевой код завершения и обратную трассировку 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 см. Вопрос о переполнении стека Как отправить почту из программы Ruby? .

Вы также можете использовать другие языки, которые поставляются с Mac OS X:

3 голосов
/ 23 декабря 2009

sendmail и даже postfix могут быть слишком большими для установки, если все, что вам нужно, - это отправить несколько писем из ваших скриптов.

Если у вас есть учетная запись Gmail , например, вы можете использовать серверы Google для отправки электронной почты, используя SMTP . Если вы не хотите использовать сервер gGoogle, если у вас есть доступ к какому-либо SMTP-серверу, он должен работать.

Очень легкая программа, которая облегчает это: msmtp . У них есть примеры файлов конфигурации в их документации .

Самый простой способ сделать это - установить общесистемное значение по умолчанию:

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

msmtp должен быть очень прост в установке. На самом деле для этого есть порт , так что это может быть так просто, как 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.

3 голосов
/ 01 декабря 2009

1) Почему бы не настроить postfix на обработку только исходящей почты и передачу ее через почтовый шлюз? Его самое большое преимущество в том, что он уже установлен на клиентах OS X.

2) Установите и настройте один из облегченных MTA, которые обрабатывают только исходящую почту, например nullmailer или ssmtp (доступно через MacPorts).

В обоих случаях используйте mailx(1) (или mutt, если хотите пофантазировать) для отправки писем из сценария оболочки.

Есть несколько вопросов о сбое сервера, которые подробно описаны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...