Надсилайте пошту з контейнера Docker з Postfix хосту


18

Я запускаю сервер Ubuntu 14.04 (Linux). Я дуже добре встановив і настроював Postfix та OpenDKIM на сервері; Я можу відправити електронну пошту до себе з такими командами, як echo hi | sendmail rootі постфікси / opendkim буде додати заголовки , такі як Message-Id, Date, і DKIM-Signature, вперед електронну пошту на мою особисту адресу електронної пошти, і все прекрасно працює.

Тепер я хотів би створити додаток, який працює в контейнері Docker і може з такою ж легкістю надсилати електронні листи. Зокрема, я не хочу турбуватися про те, як додавати заголовки на зразок Message-Id, і я не хочу робити велику конфігурацію чи встановлення програмного забезпечення всередині самого контейнера.

Який найкращий спосіб зробити це?

Чи є якийсь спосіб дозволити контейнеру виконувати виконувану sendmailроботу на хості?

Я намагався встановити з'єднання з Postfix з контейнера, використовуючи протокол SMTP на порту 25, але Postfix, здається, розглядає повідомлення, отримані таким чином, інакше; Я думаю, що він не додав заголовків, тому повідомлення було відхилено як спам від gmail (це було навіть недостатньо добре, щоб бути поміщеним у мою папку "Спам").

Тут вміст поштового журналу

Sep 28 23:35:52 dantooine postfix/smtpd[4306]: connect from unknown[172.17.0.95]
Sep 28 23:35:52 dantooine postfix/smtpd[4306]: DD457889B: client=unknown[172.17.0.95]
Sep 28 23:35:52 dantooine postfix/cleanup[4309]: DD457889B: message-id=<>
Sep 28 23:35:52 dantooine spamd[3175]: spamd: connection from localhost [::1]:59471 to port 783, fd 6
Sep 28 23:35:52 dantooine spamd[3175]: spamd: handle_user (getpwnam) unable to find user: 'someone'
Sep 28 23:35:52 dantooine spamd[3175]: spamd: still running as root: user not specified with -u, not found, or set to root, falling back to nobody
Sep 28 23:35:52 dantooine spamd[3175]: spamd: processing message (unknown) for someone:65534
Sep 28 23:35:52 dantooine spamd[3175]: spamd: clean message (2.5/5.0) for someone:65534 in 0.0 seconds, 331 bytes.
Sep 28 23:35:52 dantooine spamd[3175]: spamd: result: . 2 - MISSING_DATE,MISSING_FROM,MISSING_MID,UNPARSEABLE_RELAY scantime=0.0,size=331,user=someone,uid=65534,required_score=5.0,rhost=localhost,raddr=::1,rport=59471,mid=(unknown),autolearn=no autolearn_force=no
Sep 28 23:35:52 dantooine opendkim[3179]: DD457889B: can't determine message sender; accepting
Sep 28 23:35:53 dantooine postfix/qmgr[3664]: DD457889B: from=<whoever@example.com>, size=275, nrcpt=1 (queue active)
Sep 28 23:35:53 dantooine postfix/smtpd[4306]: disconnect from unknown[172.17.0.95]
Sep 28 23:35:53 dantooine postfix/smtp[4311]: DD457889B: to=<someone@gmail.com>, relay=gmail-smtp-in.l.google.com[2607:f8b0:4003:c05::1b]:25, delay=0.25, delays=0.12/0.01/0.03/0.09, dsn=5.7.1, status=bounced (host gmail-smtp-in.l.google.com[2607:f8b0:4003:c05::1b] said: 550-5.7.1 [fd17:8b70:893a:44bf:fe73:6c21] Our system has detected that 550-5.7.1 this message is likely unsolicited mail. To reduce the amount of spam 550-5.7.1 sent to Gmail, this message has been blocked. Please visit 550-5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for 550 5.7.1 more information. su20si7357528oeb.94 - gsmtp (in reply to end of DATA command))
Sep 28 23:35:53 dantooine postfix/cleanup[4309]: 254E688A0: message-id=<20140928233553.254E688A0@myserver.example.com>
Sep 28 23:35:53 dantooine postfix/bounce[4330]: DD457889B: sender non-delivery notification: 254E688A0
Sep 28 23:35:53 dantooine postfix/qmgr[3664]: 254E688A0: from=<>, size=3374, nrcpt=1 (queue active)
Sep 28 23:35:53 dantooine postfix/qmgr[3664]: DD457889B: removed
Sep 28 23:35:53 dantooine postfix/virtual[4331]: 254E688A0: to=<whoever@example.com>, relay=virtual, delay=0.01, delays=0/0/0/0, dsn=2.0.0, status=sent (delivered to maildir)
Sep 28 23:35:53 dantooine postfix/qmgr[3664]: 254E688A0: removed

Будь ласка, опублікуйте заголовок свого електронного листа (той, який GMAIL неправильно
визнав

Електронний лист, який я намагався надіслати, мав Toзаголовок, Subjectзаголовок та однорядковий текст. Я не впевнений, як сказати, які заголовки у нього були після того, як Postfix провів його через мілтери, знаєте як? Ось вихід у / var / log / syslog, який показує, як він оброблявся Postfix та відмовлявся Gmail: gist.github.com/DavidEGrayson/fbf65c8290c049a1f262
Девід Грейсон,

Відповіді:


8

Оскільки у вас є робоче рішення, тут я спробую пояснити іншу поведінку, коли ви звертаєтеся до postfix (SMTP) і коли ви використовуєте sendmail (не-SMTP).

FYI, OpenDKIM буде викликати постфікс із механізмом Milter . Ви можете отримати деяку інформацію про те, як реалізовується реалізація в postfix за допомогою офіційної документації . Ось діаграма гачка дози у постфіксі.

             SMTP-only       non-SMTP
             filters         filters
                ^ |            ^ |
                | v            | |
Network ->  smtpd(8)           | |
                       \       | V
Network ->  qmqpd(8)    ->  cleanup(8)  ->  incoming
                       /
            pickup(8)
               :
Local   ->  sendmail(1)

Ви можете бачити, що sendmail-шлях (не-SMTP) та telnet-шлях (SMTP) мають різний порядок обробки.

  • Електронний лист, який не є SMTP, буде оброблений очищенням, перш ніж його буде введено в доміло. Cleanup демон був відповідальний за додавання відсутніх заголовків: (Resent-) From:, To:, Message-Id:, і Дата: . Тому ваш електронний лист матиме повний заголовок при введенні в OpenDKIM промінь, навіть оригінальна електронна пошта мала неповний заголовок.

  • Електронна пошта SMTP буде введена в мельницю OpenDKIM до того, як відбудеться будь-яка обробка очищення. Тому, якщо ваш початковий електронний лист мав неповний заголовок, то opendkim може відмовитись підписувати електронний лист. From: заголовок є обов'язковим (див RFC 6376 ) , і якщо лист не має його, OpenDKIM відмовиться підписати лист і дати вам попередження

    can't determine message sender; accepting
    

Оскільки я ніколи не використовую докер, я не знаю, яке обмеження у sendmail / pickup всередині контейнера. Я думаю, що рішення Девіда Грейсона було достатньо безпечним, щоб забезпечити підписання повідомлення OpenDKIM.


Це було просвітливо; Дякую. На жаль, я досі не бачу жодного рішення краще, ніж моє поточне рішення (описане у моїй відповіді).
Девід Грейсон

Очевидною причиною було виправити додаток для додавання From:заголовка у вашу електронну пошту :)
masegaloeh

Але я також повинен був би додати речі, про Message-Idякі я не дуже багато знаю, і, певно, я помиляюся ... здається, простіше дозволити демону очищення подбати про це.
Девід Грейсон

Власне, ID повідомлення не був обов'язковим, як сказав RFC 6376 . За замовчуванням обов'язковий заголовок був лише Fromзаголовком. Але, якщо ви хочете створити свій власний ідентифікатор повідомлення, ви можете скористатись такою
masegaloeh

6

Ви повинні вказати inet_interfacesна docker bridge ( docker0) у конфігурації Postfix, розташованій у налаштуваннях/etc/postfix/main.cf

inet_interfaces = <docker0_ip>

Більше внутрішніх робочих деталей при надсиланні електронної пошти-від-докера-через-постфікса-встановленого-на-хості


Дякуємо за посилання! Відповідна частина для мене , щоб додати що - щось на зразок , 172.17.0.0/16щоб mynetworksв /etc/postfix/main.cfі service postfix restart.
JSchirrmacher

5

Це напіввідповідь, або принаймні наполовину перевірена, оскільки зараз я працюю над тією ж проблемою. Я сподіваюсь, що хтось може допомогти чітко визначити те, що я пропустив.

Відповідь з ОП (Девід Грейсон) звучить для мене як повторне винайдення поштової котушки після відстеження, але використання цієї поштової котушки звучить як багатообіцяючий підхід, тому ось до чого я дійшов.

Інтерфейс сумісності / usr / bin / sendmail, що надається postfix, передає пошту postdrop, яка є жорсткою відстрочкою, що дозволяє їй зберігати пошту у черзі Maildrop за адресою / var / spool / postfix / maildrop. Це має відбуватися в докерній ємності. Решта постфіксу, сподіваємось, не повинні працювати у контейнері.

Отже, я розміщую хостинг / var / spool / postfix / maildrop та / var / spool / postfix / public. Я можу отримати пошту, яка доставляється до / var / spool / postfix / maildrop у середовищі хоста, оскільки я встановив каталог черги maildrop. Оскільки я встановив /var/spool/postfix/public, maildropможе сигналізувати pickupпро збирання пошти з черги. На жаль, задіяні uids та gids, якщо я не подбаю про це, це означає, що пікап у каталозі хосту не може прочитати файли котушки, а ще гірше, що встановлення postfix зіпсує дозволи на каталог maildrop у середовищі хоста.

Але це, здається, працює:

$ cat Dockerfile 
FROM debian:jessie
# Ids from parent environment

    RUN groupadd -g 124 postfix && \
        groupadd -g 125 postdrop && \
    useradd -u 116 -g 124 postfix

    RUN apt-get update && \
      DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
        postfix \
        bsd-mailx

    CMD echo test mail | mail myemail@example.com

$ sudo docker build   .
...
Successfully built 16316fcd44b6

$ sudo docker run   -v /var/spool/postfix/maildrop:/var/spool/postfix/maildrop \
  -v /var/spool/postfix/public:/var/spool/postfix/public 16316fcd44b6

Хоча це працює, я не дуже задоволений жорстким кодуванням уідів та діток. Це означає, що один і той же контейнер не може бути зарахований до того, що він буде працювати однаково скрізь. Я вважаю, що якщо замість того, щоб встановлювати об'єм з хоста, я монтую його з контейнера, в якому працює постфікс, він ніколи не буде конфліктувати, і мені потрібна лише одна установка постфікса, щоб отримати пошту з багатьох контейнерів. Я встановив би ці утиди та діджі в базовому зображенні, від якого успадковують усі мої контейнери.

Мені цікаво, хоча це справді хороший підхід. З такою простою конфігурацією пошти та відсутністю демона, який використовується на контейнері для повторної спроби доставки, більш простий локальний MTA, як msmtp, може бути більш підходящим. Він буде доставляти через TCP реле на тому ж хості, де відбудеться спулінг.

До проблем із підходом msmtp належать:

  • більше можливості втратити пошту, якщо ретранслятор smtp, який він надсилає, недоступний. Якщо це реле одного і того ж хоста, то ймовірність виникнення проблем із мережею низька, але я повинен бути обережним, як я перезапустив контейнер реле.
  • виконання?
  • Якщо велика кількість поштових повідомлень проходить, поштова пошта починає скидати?

Загалом, схожий підхід до спільної коробки спільного постфікса представляється нестабільною конфігурацією для налаштування, але менше шансів вийти з ладу під час запуску (ретрансляція недоступна, тому пошта відпала).


4

Я вирішив, що спосіб, яким контейнер буде надсилати пошту, - це записати його у файл у певному каталозі, який буде доступний як контейнеру, так і хосту як "том" Docker.

Я створив скрипт оболонки під назвою mailsender.sh, який читає пошти із визначеного каталогу, надсилає їх на sendmail, а потім видаляє їх:

#!/bin/bash
# Runs on the host system, reading mails files from a directory
# and piping them to sendmail -t and then deleting them.

DIR=$1

if [ \! \( -d "$DIR" -a -w "$DIR" \) ]
then
  echo "Invalid directory given: $DIR"
  exit 1
fi

echo "`date`: Starting mailsender on directory $DIR"

cd $DIR

while :
do
  for file in `find . -maxdepth 1 -type f`
  do
    echo "`date`: Sending $file"
    sendmail -t < $file
    rm $file
  done
  sleep 1
done

Ubuntu використовує початковий старт, тому я створив файл, названий /etc/init/mailsender.confдля перетворення цього сценарію в демон:

description "sends mails from directory"
start on stopped rc RUNLEVEL=[2345]
stop on runlevel[!2345]
respawn
exec start-stop-daemon --start --make-pidfile --pidfile /var/run/mailsender.pid --exec
/path/to/mailsender.sh /var/mailsend

Я можу почати послугу start mailsenderі зупинити її stop mailsender. Я можу переглянути його журнали /var/log/upstart/mailsender.log, і, звичайно, можу відстежувати його, використовуючи файл PID.

Вам потрібно створити /var/mailsendкаталог, а потім зробити його доступним з контейнера Docker, додавши аргумент -v /var/mailsend:/var/mailsendу вашу docker runкоманду.


Можливо, щось на кшталт mini_sendmail буде корисним? Він використовується в контейнерах, як міст між контейнером, ізольованим додатком та демоном сервера sendmail в системі хостів контейнерів. cyberciti.biz/tips/… acme.com/software/mini_sendmail
Мікль

Якщо він надсилає повідомлення до Postfix через SMTP, я не думаю, що Postfix очистить електронну пошту. Можливо, якби у вас був MTA, який був більш налаштований (або ми з'ясували, як краще налаштувати Postfix), він би спрацював.
Девід Грейсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.