Wyślij pocztę z kontenera Docker z Postfixem hosta


18

Korzystam z serwera Ubuntu 14.04 (Linux). Zainstalowałem i skonfigurowałem Postfix i OpenDKIM bardzo ładnie na serwerze; Mogę wysyłać e-maile do siebie za pomocą poleceń takich jak echo hi | sendmail root, i postfix / opendkim doda nagłówki takie jak Message-Id, Datei DKIM-Signature, przesyła e-maila do mojego osobistego adresu e-mail, a wszystko działa świetnie.

Teraz chciałbym utworzyć aplikację, która działa w kontenerze Docker i może wysyłać wiadomości e-mail z taką samą łatwością. W szczególności nie chcę się martwić dodawaniem nagłówków, takich jak Message-Id, i nie chcę przeprowadzać dużej konfiguracji ani instalacji oprogramowania w samym kontenerze.

Jak najlepiej to zrobić?

Czy jest jakiś sposób, aby kontener mógł uruchomić sendmailwymaganie na hoście?

Próbowałem nawiązać połączenie z Postfix z kontenera za pomocą protokołu SMTP na porcie 25, ale Postfix wydaje się traktować wiadomości otrzymane w ten sposób inaczej; Myślę, że nie dodał żadnych nagłówków, więc wiadomość została odrzucona jako spam przez Gmaila (nie była nawet wystarczająco dobra, aby umieścić ją w folderze Spam).

Oto treść 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

Proszę zamieścić nagłówek e-maila (ten, który został błędnie zidentyfikowany jako spam przez GMAIL)
masegaloeh

Wiadomość e-mail, którą próbowałem wysłać, zawierała tylko Tonagłówek, Subjectnagłówek i treść jednowierszową. Nie jestem pewien, jak powiedzieć, jakie nagłówki miał po tym, jak Postfix przejrzał go przez miltersy, wiesz jak? Oto wynik w / var / log / syslog pokazujący, jak został przetworzony przez Postfix i odrzucony przez Gmaila: gist.github.com/DavidEGrayson/fbf65c8290c049a1f262
David Grayson

Odpowiedzi:


8

Ponieważ masz działające rozwiązanie, w tym miejscu postaram się wyjaśnić inne zachowanie podczas łączenia się telnet z postfixem (SMTP) i podczas korzystania z sendmaila (nie SMTP).

Do Twojej wiadomości, OpenDKIM zostanie wywołany przez postfiks z mechanizmem Miltera . Możesz uzyskać informacje o tym, jak milter implementacji w Postfiksie za pośrednictwem tej oficjalnej dokumentacji . Oto schemat haka miltera w postfiksie.

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

Widać, że sendmail-way (non-SMTP) i telnet-way (SMTP) ma inną kolejność przetwarzania.

  • Wiadomość e-mail inna niż SMTP zostanie przetworzona przez czyszczenie przed wstrzyknięciem do programu milter. Oczyszczanie demon był odpowiedzialny za dodanie brakujących nagłówków: (Resent-) Od :, Do :, Message-ID :, i Data: . Dlatego twój e-mail będzie miał pełny nagłówek po wstrzyknięciu do OpenDKIM, nawet oryginalny e-mail miał niekompletny nagłówek.

  • Wiadomość e-mail SMTP zostanie wstrzyknięta do Miltera OpenDKIM przed jakimkolwiek przetwarzaniem czyszczenia. Dlatego jeśli twój oryginalny e-mail miał niekompletny nagłówek, opendkim może odmówić podpisania e-maila. From: header było obowiązkowe (patrz RFC 6376 ) oraz jeśli e-mail nie ma, OpenDKIM odmówi podpisania e-mail i daje ostrzeżenie

    can't determine message sender; accepting
    

Ponieważ nigdy nie korzystam z dokera, nie wiem, jakie ograniczenie wysyłania / odbierania w kontenerze. Myślę, że obejście Davida Graysona było wystarczająco bezpieczne, aby zapewnić podpisanie wiadomości przez OpenDKIM.


To było pouczające; Dziękuję Ci. Niestety nadal nie widzę żadnego lepszego rozwiązania niż moje obecne rozwiązanie (opisane w mojej odpowiedzi).
David Grayson

Oczywistym powodem było naprawienie dodawania From:nagłówka w e
mailu

Ale musiałbym również dodać takie rzeczy, o Message-Idktórych nie wiem zbyt wiele i prawdopodobnie pomyliłbym się… wydaje się, że łatwiej jest zająć się tym demon czyszczenia.
David Grayson

W rzeczywistości komunikat Message-ID nie był obowiązkowy, jak powiedział RFC 6376 . Domyślnie obowiązkowy nagłówek był tylko Fromnagłówkiem. Ale jeśli chcesz wygenerować własny identyfikator wiadomości, możesz użyć rekomendacji takiej jak ten IETF Draft
masegaloeh


5

To jest połowa odpowiedzi lub przynajmniej połowa przetestowana, ponieważ obecnie pracuję nad tym samym problemem. Mam nadzieję, że ktoś może pomóc w zrozumieniu tego, co przegapiłem.

Odpowiedź od OP (David Grayson) brzmi dla mnie jak ponowne wynalezienie szpuli pocztowej, ale użycie tej szpuli brzmi jak obiecujące podejście, więc tutaj doszedłem.

Interfejs kompatybilności / usr / bin / sendmail zapewniany przez postfix przekazuje pocztę do postdropa, czyli sgid postdrop, pozwalając mu przechowywać pocztę w kolejce maildrop w / var / spool / postfix / maildrop. Powinno to nastąpić w kontenerze dokera. Pozostała część postfiksa nie powinna być uruchamiana w kontenerze.

Więc jestem hostem montującym / var / spool / postfix / maildrop i / var / spool / postfix / public. Mogę dostać pocztę dostarczoną do / var / spool / postfix / maildrop w środowisku hosta, ponieważ zamontowałem katalog kolejek maildrop. Ponieważ mam zamontowane /var/spool/postfix/public, maildropmoże sygnalizować, pickupaby odebrać pocztę z kolejki. Niestety, zaangażowane identyfikatory i identyfikatory, chyba że się tym zajmę, co oznacza, że ​​pobieranie w katalogu hosta nie może odczytać zbiorów buforowych, a co gorsza instalacja Postfiksa zakłóca uprawnienia do katalogu maildrop w środowisku hosta.

Wydaje się jednak, że to działa:

$ 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

Chociaż działa, nie jestem zbytnio zadowolony z twardego kodowania UID i GID. Oznacza to, że nie można policzyć tego samego kontenera, aby uruchomić go wszędzie. Wydaje mi się jednak, że jeśli zamiast montować wolumin z hosta, podłączę go z kontenera z postfixem, to nigdy nie spowoduje konfliktu i potrzebuję tylko jednej instalacji postfixa, aby wydostać pocztę z wielu kontenerów. Uids i gids ustawię na podstawowym obrazie, z którego odziedziczą wszystkie moje pojemniki.

Zastanawiam się jednak, czy to naprawdę dobre podejście. Przy tak prostej konfiguracji poczty i braku kontenera używanego w kontenerze do ponownej próby dostarczenia, bardziej odpowiedni może być prostszy lokalny MTA, taki jak msmtp. Dostarczałby przez TCP do przekaźnika na tym samym hoście, gdzie miałoby miejsce buforowanie.

Obawy związane z podejściem msmtp obejmują:

  • większa możliwość utraty poczty, jeśli przekaźnik smtp, do którego wysyła, nie jest dostępny. Jeśli jest to przekaźnik na tym samym hoście, szansa na problemy z siecią jest niewielka, ale musiałbym uważać na to, jak zrestartowałem pojemnik przekaźnika.
  • występ?
  • Jeśli przejdzie duża seria poczty, czy poczta zacznie być upuszczana?

Ogólnie rzecz biorąc, współużytkowane buforowanie postfiksów wydaje się bardziej prawdopodobne, że jest to delikatna konfiguracja do skonfigurowania, ale rzadziej zawiedzie w czasie wykonywania (przekaźnik niedostępny, więc poczta spadła).


4

Zdecydowałem, że sposób, w jaki kontener wysyła pocztę, polega na zapisaniu jej do pliku w określonym katalogu, który będzie dostępny zarówno z kontenera, jak i hosta jako „wolumin” Dockera.

Stworzyłem skrypt powłoki o nazwie mailsender.sh, który odczytuje wiadomości z określonego katalogu, wysyła je do sendmaila, a następnie usuwa je:

#!/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 używa upstart, więc utworzyłem plik o nazwie, /etc/init/mailsender.confaby zmienić ten skrypt w demona:

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

Mogę uruchomić usługę start mailsenderi zatrzymać ją stop mailsender. Mogę patrzeć na jego logi /var/log/upstart/mailsender.logi oczywiście mogę monitorować za pomocą pliku PID.

Musisz utworzyć /var/mailsendkatalog, a następnie udostępnić go z kontenera Docker, dodając argument -v /var/mailsend:/var/mailsenddo docker runpolecenia.


Może coś takiego jak mini_sendmail będzie pomocne? Jest używany w kontenerach, takich jak pomost między izolowaną aplikacją kontenerów a demonem serwera sendmail w systemie hosta kontenerów. cyberciti.biz/tips/… acme.com/software/mini_sendmail
Mikl

Jeśli wysyła wiadomość e-mail do Postfix za pośrednictwem SMTP, nie sądzę, że Postfix wyczyści wiadomość e-mail. Może gdybyś miał MTA, który był bardziej konfigurowalny (lub ustaliliśmy, jak lepiej skonfigurować Postfix), to zadziałałoby.
David Grayson,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.