Kirim email dari wadah Docker dengan Postfix host


18

Saya menjalankan server Ubuntu 14.04 (Linux). Saya telah menginstal dan mengkonfigurasi Postfix dan OpenDKIM dengan sangat baik di server; Saya dapat mengirim email ke diri dengan perintah seperti echo hi | sendmail root, dan postfix / opendkim akan menambahkan header seperti Message-Id, Date, dan DKIM-Signature, meneruskan email ke alamat email pribadi saya, dan semuanya bekerja besar.

Sekarang saya ingin membuat aplikasi yang berjalan dalam wadah Docker dan dapat mengirim email dengan mudah. Secara khusus, saya tidak ingin khawatir tentang menambahkan header seperti Message-Id, dan saya tidak ingin melakukan banyak konfigurasi atau instalasi perangkat lunak di dalam wadah itu sendiri.

Apa cara terbaik untuk melakukan ini?

Apakah ada cara untuk membiarkan kontainer menjalankan sendmailexectuable pada host?

Saya mencoba membuat koneksi ke Postfix dari sebuah wadah menggunakan protokol SMTP pada port 25, tetapi Postfix tampaknya memperlakukan pesan yang diterima dengan cara yang berbeda; Saya pikir itu tidak menambahkan header sehingga pesan langsung ditolak sebagai spam oleh gmail (itu bahkan tidak cukup baik untuk dimasukkan ke folder Spam saya).

Di sini konten maillog

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

Silakan kirim tajuk email Anda (email yang salah diidentifikasi sebagai spam oleh GMAIL)
masegaloeh

Email yang saya coba kirim hanya memiliki Totajuk, Subjecttajuk, dan satu baris. Saya tidak yakin bagaimana cara mengetahui header apa yang dimilikinya setelah Postfix menjalankannya melalui milters, apakah Anda tahu caranya? Ini adalah keluaran di / var / log / syslog yang menunjukkan bagaimana prosesnya oleh Postfix dan ditolak oleh Gmail: gist.github.com/DavidEGrayson/fbf65c8290c049a1f262
David Grayson

Jawaban:


8

Karena Anda memiliki solusi yang berfungsi, di sini saya akan mencoba menjelaskan perilaku yang berbeda ketika Anda telnet ke postfix (SMTP) dan ketika Anda menggunakan sendmail (non-SMTP).

FYI, OpenDKIM akan dipanggil oleh postfix dengan mekanisme Milter . Anda bisa mendapatkan info bagaimana implementasi yang lebih ringan di postfix melalui dokumentasi resmi ini . Di sini diagram dari kait kait dalam postfix.

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

Anda dapat melihat bahwa sendmail-way (non-SMTP) dan telnet-way (SMTP) memiliki urutan pemrosesan yang berbeda.

  • Email non-SMTP akan diproses dengan pembersihan sebelum disuntikkan ke milter. Daemon cleanup bertanggung jawab untuk menambahkan header hilang: (Resent-) Dari :, Untuk :, Pesan-Id :, dan Tanggal: . Karenanya email Anda akan memiliki tajuk lengkap ketika disuntikkan ke OpenDKIM milter, bahkan email asli pun memiliki tajuk tidak lengkap.

  • Email SMTP akan disuntikkan ke OpenDKIM milter sebelum pemrosesan pembersihan dilakukan. Karenanya, jika email asli Anda memiliki tajuk yang tidak lengkap, maka opendkim dapat menolak untuk menandatangani email. The Dari: Header adalah wajib (lihat RFC 6376 ) dan jika email tidak memilikinya, OpenDKIM akan menolak untuk menandatangani email dan memberikan peringatan

    can't determine message sender; accepting
    

Karena saya tidak pernah menggunakan buruh pelabuhan, saya tidak tahu apa batasan sendmail / pickup di dalam wadah. Saya pikir solusi David Grayson cukup aman untuk memastikan bahwa OpenDKIM menandatangani pesan.


Itu mencerahkan; Terima kasih. Sayangnya, saya masih tidak melihat solusi apa pun yang lebih baik daripada solusi saya saat ini (dijelaskan dalam jawaban saya).
David Grayson

Alasan yang jelas adalah memperbaiki aplikasi untuk menambahkan From:header di email Anda :)
masegaloeh

Tetapi saya juga harus menambahkan hal-hal seperti Message-Idyang saya tidak tahu banyak tentang dan saya mungkin akan salah ... sepertinya lebih mudah untuk membiarkan daemon pembersihan mengurus hal itu.
David Grayson

Sebenarnya, Message-ID tidak wajib seperti yang dikatakan RFC 6376 . Secara default, header wajib hanya Fromheader. Tapi, jika Anda ingin membuat ID-Pesan Anda sendiri, Anda dapat menggunakan rekomendasi seperti Draft IETF ini
masegaloeh

6

Anda harus menunjuk inet_interfaceske docker bridge ( docker0) di konfigurasi postfix yang terletak di set/etc/postfix/main.cf

inet_interfaces = <docker0_ip>

Detail kerja internal yang lebih banyak pada pengiriman-email-dari-docker-melalui-postfix-instal-di-host


Terima kasih untuk tautannya! Bagian yang relevan bagi saya adalah untuk menambahkan sesuatu seperti 172.17.0.0/16untuk mynetworksdi /etc/postfix/main.cfdan service postfix restart.
JSchirrmacher

5

Ini adalah setengah jawaban, atau setidaknya setengah diuji, karena saya saat ini sedang mengerjakan masalah yang sama. Saya berharap seseorang dapat membantu menyempurnakan apa yang saya lewatkan.

Jawaban dari OP (David Grayson) bagi saya terdengar seperti penemuan ulang spool mail postdrop, tetapi menggunakan spool mail itu kedengarannya seperti pendekatan yang menjanjikan, jadi di sinilah saya mendapatkan.

Antarmuka kompatibilitas / usr / bin / sendmail yang disediakan oleh postfix meneruskan mail ke postdrop, yang merupakan postdrop sgid, memungkinkannya untuk menyimpan email ke dalam antrian maildrop di / var / spool / postfix / maildrop. Ini harus terjadi dalam wadah buruh pelabuhan. Sisa postfix semestinya tidak harus berjalan dalam wadah.

Jadi, saya host host / var / spool / postfix / maildrop dan / var / spool / postfix / public. Saya dapat mengirim surat ke / var / spool / postfix / maildrop di lingkungan host, karena saya telah memasang direktori antrian maildrop. Karena saya sudah mount /var/spool/postfix/public, maildropbisa memberi sinyal pickupuntuk mengumpulkan email dari antrian. Sayangnya, uids dan gids terlibat kecuali saya mengatasinya, artinya pickup di direktori host tidak dapat membaca file spool, dan lebih buruk lagi instalasi postfix mengacaukan izin pada direktori maildrop di lingkungan host.

Namun, ini sepertinya berhasil:

$ 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

Sementara itu berfungsi, saya tidak terlalu senang dengan pengkodean yang sulit pada uids dan gids. Ini berarti bahwa wadah yang sama tidak dapat dihitung untuk menjalankan yang sama di mana-mana. Saya pikir meskipun jika daripada memasang volume dari host saya me-mount-nya dari sebuah wadah yang menjalankan postfix, maka itu tidak akan pernah konflik, dan saya hanya perlu satu instalasi postfix untuk mengeluarkan email dari banyak kontainer. Saya akan mengatur uids dan gids dalam gambar dasar yang menjadi asal semua wadah saya.

Saya bertanya-tanya apakah ini benar-benar pendekatan yang bagus. Dengan konfigurasi surat yang begitu sederhana, dan tidak ada daemon yang digunakan pada wadah untuk mencoba ulang pengiriman, MTA lokal yang lebih sederhana seperti msmtp mungkin lebih tepat. Itu akan mengirimkan melalui TCP ke relay pada host yang sama, di mana spooling akan terjadi.

Kekhawatiran dengan pendekatan msmtp meliputi:

  • lebih banyak kemungkinan kehilangan email jika smtp relay yang dikirimkannya tidak tersedia. Jika itu relay pada host yang sama, maka kemungkinan masalah jaringan rendah, tetapi saya harus berhati-hati tentang bagaimana saya me-restart wadah relay.
  • kinerja?
  • Jika ledakan besar surat lewat, apakah surat mulai dijatuhkan?

Secara umum, pendekatan spool postfix bersama tampaknya lebih cenderung menjadi konfigurasi rapuh untuk diatur, tetapi lebih kecil kemungkinannya gagal pada waktu berjalan (relai tidak tersedia, jadi surat dijatuhkan).


4

Saya memutuskan bahwa cara wadah akan mengirim surat adalah dengan menuliskannya ke file di direktori tertentu, yang akan dapat diakses dari wadah dan host sebagai "volume" Docker.

Saya membuat skrip shell bernama mailsender.sh yang membaca email dari direktori yang ditentukan, mengirimkannya ke sendmail, dan kemudian menghapusnya:

#!/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 menggunakan pemula, jadi saya membuat file bernama /etc/init/mailsender.confuntuk mengubah skrip ini menjadi daemon:

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

Saya dapat memulai layanan dengan start mailsenderdan menghentikannya stop mailsender. Saya dapat melihat log-nya /var/log/upstart/mailsender.log, dan tentu saja saya bisa memantaunya menggunakan file PID.

Anda perlu membuat /var/mailsenddirektori dan membuatnya dapat diakses dari wadah Docker dengan menambahkan argumen -v /var/mailsend:/var/mailsendke docker runperintah Anda .


Mungkin sesuatu seperti mini_sendmail akan sangat membantu? Ini digunakan dalam wadah, seperti jembatan antara aplikasi kontainer terisolasi dan daemon server sendmail pada sistem host kontainer. cyberciti.biz/tips/… acme.com/software/mini_sendmail
Mikl

Jika mengirim email ke Postfix melalui SMTP, saya rasa Postfix tidak akan membersihkan email. Mungkin jika Anda memiliki MTA yang lebih dapat dikonfigurasi (atau kami menemukan cara mengkonfigurasi Postfix yang lebih baik) itu akan berhasil.
David Grayson
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.