Kirim email dari kontainer Docker dengan Postfix host

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

Sekarang saya ingin membuat aplikasi yang berjalan di Docker wadah dan dapat mengirim email dengan kemudahan yang sama. 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 wadah menjalankan sendmail exectuable pada host?

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

Berikut isi 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 6Sep 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 nobodySep 28 23:35:52 dantooine spamd[3175]: spamd: processing message (unknown) for someone:65534Sep 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=noSep 28 23:35:52 dantooine opendkim[3179]: DD457889B: can't determine message sender; acceptingSep 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: 254E688A0Sep 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: removedSep 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

Anda harus menunjuk inet_interfaces untuk jembatan docker (docker0) dalam konfigurasi postfix yang terletak di set /etc/postfix/main.cf

inet_interfaces = <docker0_ip>

Lebih detail kerja internal di mengirim-email-dari-docker-melalui-postfix-diinstal-pada-host

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 ikan jantan. Anda bisa mendapatkan beberapa info bagaimana implementasi ikan jantan di postfix melalui ini dokumentasi resmi. Berikut diagram dari ikan jantan kait di postfix.

             SMTP-only       non-SMTP             filters         filters                ^ |            ^ |                | v            | |Network ->  smtpd(8)           | |                       \       | VNetwork ->  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 ikan jantan. Pembersihan daemon bertanggung jawab untuk menambahkan header yang hilang: (Membenci-) Dari:, Untuk:, Pesan-Id:, dan Tanggal:. Oleh karena itu email Anda akan memiliki header yang lengkap ketika disuntikkan ke opendkim ikan jantan bahkan email asli memiliki header yang tidak lengkap.

  • Email SMTP akan disuntikkan ke opendkim ikan jantan sebelum proses pembersihan berlangsung. Oleh karena itu, jika email asli Anda memiliki header 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 memberi Anda peringatan

      can't determine message sender; accepting

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

Saya memutuskan bahwa cara wadah akan mengirim email adalah dengan menulisnya ke file di direktori tertentu, yang akan dapat diakses dari wadah dan host sebagai "volume"buruh pelabuhan.

Saya membuat skrip shell yang disebut mailsender.sh yang berbunyi mail dari direktori tertentu, mengirimkannya ke sendmail, dan kemudian menghapus mereka:

#!/bin/bash# Runs on the host system, reading mails files from a directory# and piping them to sendmail -t and then deleting them.DIR=$1if [ \! \( -d "$DIR" -a -w "$DIR" \) ]then  echo "Invalid directory given: $DIR"  exit 1fiecho "`date`: Starting mailsender on directory $DIR"cd $DIRwhile :do  for file in `find . -maxdepth 1 -type f`  do    echo "`date`: Sending $file"    sendmail -t < $file    rm $file  done  sleep 1done

Ubuntu menggunakan upstart jadi saya membuat file bernama /etc/init/mailsender.conf untuk mengubah script ini menjadi daemon:

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

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

Anda perlu membuat /var/mailsend direktori dan kemudian membuatnya dapat diakses dari wadah Docker dengan menambahkan argumen -v /var/mailsend:/var/mailsend untuk Anda docker run perintah.

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

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

Antarmuka kompatibilitas/usr/bin / sendmail yang disediakan oleh postfix meneruskan email ke postdrop, yaitu sgid postdrop, memungkinkannya untuk menyimpan email ke dalam antrian maildrop di /var/spool/postfix/maildrop. Ini harus terjadi dalam wadah docker. Sisa postfix semoga tidak harus dijalankan dalam wadah.

Jadi, saya memasang host / var/spool/postfix /maildrop dan/var/spool/postfix / public. Saya bisa mendapatkan email yang dikirim ke / var/spool/postfix / maildrop di lingkungan host, karena saya telah memasang direktori antrian maildrop. Karena saya telah memasang /var/spool/postfix/public, maildrop bisa sinyal pickup untuk mengumpulkan surat dari antrian. Sayangnya, UID dan GID terlibat kecuali saya mengurusnya, yang berarti bahwa 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 tampaknya 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

Meskipun berhasil, saya tidak terlalu senang dengan pengkodean keras UID dan GID. Ini berarti bahwa wadah yang sama tidak dapat dihitung untuk menjalankan yang sama di mana-mana. Saya pikir Meskipun jika alih-alih memasang volume dari host saya memasangnya dari wadah yang menjalankan postfix, maka itu tidak akan pernah bertentangan, dan saya hanya perlu satu instalasi postfix untuk mengeluarkan surat dari banyak wadah. Saya akan mengatur UID dan GID tersebut dalam gambar dasar yang diwarisi dari semua wadah saya.

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

Kekhawatiran dengan pendekatan msmtp meliputi:

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

Secara umum, pendekatan spool postfix bersama tampaknya lebih cenderung menjadi konfigurasi yang rapuh untuk disiapkan, tetapi kecil kemungkinannya gagal pada waktu proses (relai tidak tersedia, sehingga email terputus).

Silakan posting header email anda (yang salah diidentifikasi sebagai spam oleh GMAIL)

Email yang saya coba kirim Hanya memiliki tajuk 'ke`, tajuk ‘subjek’, dan badan satu baris. Saya Tidak yakin bagaimana cara mengetahui header apa yang dimilikinya setelah Postfix menjalankannya melalui milters, tahukah anda caranya? Berikut adalah output di / var / log / syslog yang menunjukkan bagaimana itu diproses oleh Postfix dan ditolak oleh Gmail: log.txt · GitHub