Gửi thư từ container Docker với Postfix của máy chủ


18

Tôi đang chạy máy chủ Ubuntu 14.04 (Linux). Tôi đã cài đặt và cấu hình PostfixOpenDKIM rất độc đáo trên máy chủ; Tôi có thể gửi email cho bản thân mình với các lệnh như echo hi | sendmail root, và postfix / opendkim sẽ thêm tiêu đề như Message-Id, DateDKIM-Signature, về phía trước email đến địa chỉ email cá nhân của tôi, và tất cả mọi thứ hoạt động tốt.

Bây giờ tôi muốn tạo một ứng dụng chạy trong bộ chứa Docker và có thể gửi email một cách dễ dàng. Cụ thể, tôi không muốn lo lắng về việc thêm các tiêu đề như thế nào Message-Idvà tôi không muốn cài đặt phần mềm hoặc cấu hình bên trong thùng chứa.

Cách tốt nhất để làm việc này là gì?

Có cách nào để cho container chạy sendmailexectuable trên máy chủ không?

Tôi đã thử tạo kết nối với Postfix từ một container bằng giao thức SMTP trên cổng 25, nhưng Postfix dường như xử lý các tin nhắn nhận được theo cách khác; Tôi nghĩ rằng nó đã không thêm bất kỳ tiêu đề nào nên tin nhắn đã bị từ chối hoàn toàn là spam bởi gmail (nó thậm chí không đủ tốt để được đặt vào thư mục Spam của tôi).

Ở đây nội dung 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

Vui lòng gửi tiêu đề email của bạn (thư được xác định nhầm là thư rác bởi GMAIL)
masegaloeh

Email tôi đang cố gửi chỉ có Totiêu đề, Subjecttiêu đề và nội dung một dòng. Tôi không chắc làm thế nào để biết những tiêu đề mà nó có sau khi Postfix chạy nó thông qua các bộ lọc, bạn có biết làm thế nào không? Đây là đầu ra trong / var / log / syslog cho thấy cách nó được xử lý bởi Postfix và bị Gmail từ chối: gist.github.com/DavidEGrayson/fbf65c8290c049a1f262
David Grayson

Câu trả lời:


8

Bởi vì bạn có một giải pháp làm việc, ở đây tôi sẽ cố gắng giải thích các hành vi khác nhau khi bạn telnet đến postfix (SMTP) và khi bạn sử dụng sendmail (không phải là SMTP).

FYI, OpenDKIM sẽ được gọi bằng postfix với cơ chế Milter . Bạn có thể nhận được một số thông tin về cách thực hiện milter trong postfix thông qua tài liệu chính thức này . Ở đây sơ đồ của móc sữa trong postfix.

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

Bạn có thể thấy rằng sendmail-way (không phải là SMTP) và telnet-way (SMTP) có thứ tự xử lý khác nhau.

  • Email không phải là SMTP sẽ được xử lý bằng cách dọn dẹp trước khi đưa vào máy vắt sữa. Trình nền dọn dẹp chịu trách nhiệm thêm các tiêu đề bị thiếu: (Resent-) Từ:, To:, Message-Id:,Date : . Do đó, email của bạn sẽ có tiêu đề hoàn chỉnh khi được đưa vào bộ lọc OpenDKIM ngay cả email gốc có tiêu đề không đầy đủ.

  • Email SMTP sẽ được thêm vào bộ lọc OpenDKIM trước khi bất kỳ quá trình xử lý dọn dẹp nào diễn ra. Do đó, nếu email gốc của bạn có tiêu đề không đầy đủ thì opendkim có thể từ chối ký email. Các Từ: tiêu đề là bắt buộc (xem RFC 6376 ) và nếu một email không có nó, OpenDKIM sẽ từ chối ký vào email và cung cấp cho bạn một cảnh báo

    can't determine message sender; accepting
    

Vì tôi không bao giờ sử dụng docker, nên tôi không biết giới hạn nào đối với sendmail / đón trong container. Tôi nghĩ cách giải quyết của David Grayson đủ an toàn để đảm bảo rằng OpenDKIM ký tin nhắn.


Đó là sự giác ngộ; cảm ơn bạn. Thật không may, tôi vẫn không thấy bất kỳ giải pháp nào tốt hơn giải pháp hiện tại của mình (được mô tả trong câu trả lời của tôi).
David Grayson

Lý do rõ ràng là sửa ứng dụng để thêm From:tiêu đề vào email của bạn :)
masegaloeh

Nhưng tôi cũng sẽ phải thêm những thứ Message-Idmà tôi không biết nhiều và có lẽ tôi đã hiểu sai ... có vẻ dễ dàng hơn khi để daemon dọn dẹp chăm sóc điều đó.
David Grayson

Trên thực tế, Message-ID không bắt buộc như RFC 6376 đã nói. Theo mặc định, tiêu đề bắt buộc chỉ là Fromtiêu đề. Nhưng, nếu bạn muốn tạo ID tin nhắn của riêng mình, bạn có thể sử dụng đề xuất như Dự thảo IETF này
masegaloeh

6

Bạn phải trỏ inet_interfacesđến docker Bridge ( docker0) trong cấu hình postfix được đặt tại set/etc/postfix/main.cf

inet_interfaces = <docker0_ip>

Chi tiết làm việc nội bộ hơn khi gửi email-từ-docker-qua-postfix-install-on-the-host


Cảm ơn các liên kết! Phần liên quan đối với tôi là để thêm một cái gì đó như 172.17.0.0/16để mynetworks/etc/postfix/main.cfservice postfix restart.
JSchirrmacher

5

Đây là một nửa câu trả lời, hoặc ít nhất là một nửa đã được kiểm tra, vì tôi hiện đang làm việc với cùng một vấn đề. Tôi hy vọng ai đó có thể giúp đỡ những gì tôi đã bỏ lỡ.

Câu trả lời từ OP (David Grayson) đối với tôi giống như một phát minh lại của hộp thư bưu chính, nhưng sử dụng bộ đệm thư đó nghe có vẻ như là một cách tiếp cận đầy hứa hẹn, vì vậy đây là nơi tôi đã đến.

Giao diện tương thích / usr / bin / sendmail được cung cấp bởi postfix chuyển thư đến postdrop, đó là postg sgid, cho phép nó lưu trữ thư vào hàng đợi mail tại / var / spool / postfix / maildrop. Điều này sẽ xảy ra trong container docker. Phần còn lại của postfix hy vọng không phải chạy trong container.

Vì vậy, tôi đang lưu trữ máy chủ / var / spool / postfix / maildrop và / var / spool / postfix / public. Tôi có thể nhận thư được gửi đến / var / spool / postfix / maildrop trong môi trường máy chủ, vì tôi đã gắn thư mục hàng đợi thư. Bởi vì tôi đã gắn kết /var/spool/postfix/public, maildropcó thể báo hiệu pickupđể thu thập thư từ hàng đợi. Thật không may, các uids và gids liên quan trừ khi tôi quan tâm đến điều đó, có nghĩa là bộ thu trong thư mục máy chủ không thể đọc các tập tin spool, và tệ hơn là cài đặt postfix làm rối các quyền trên thư mục maildrop trong môi trường máy chủ.

Tuy nhiên, điều này dường như hoạt động:

$ 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

Trong khi nó hoạt động, tôi không hài lòng lắm với việc mã hóa các uids và gids. Điều này có nghĩa là cùng một container không thể được tính để chạy giống nhau ở mọi nơi. Tôi nghĩ rằng nếu thay vì gắn âm lượng từ máy chủ lưu trữ, tôi gắn nó từ một thùng chứa chạy hậu tố, thì nó sẽ không bao giờ bị xung đột và tôi chỉ cần một cài đặt hậu tố để nhận thư từ nhiều container. Tôi đã đặt những uids và gids đó trong một hình ảnh cơ bản mà tất cả các container của tôi thừa hưởng từ đó.

Tôi tự hỏi mặc dù nếu đây thực sự là một cách tiếp cận tốt. Với cấu hình thư đơn giản như vậy và không có daemon nào được sử dụng trên container để thử lại phân phối, một MTA cục bộ đơn giản hơn như msmtp có thể phù hợp hơn. Nó sẽ phân phối thông qua TCP đến một rơle trên cùng một máy chủ, nơi sẽ xảy ra hiện tượng lưu thông.

Mối quan tâm với phương pháp msmtp bao gồm:

  • nhiều khả năng mất thư nếu chuyển tiếp smtp mà nó gửi đến không khả dụng. Nếu đó là một rơle trên cùng một máy chủ thì khả năng xảy ra sự cố mạng là thấp, nhưng tôi phải cẩn thận về cách tôi khởi động lại thùng chứa rơle.
  • hiệu suất?
  • Nếu một loạt thư lớn đi qua, thư có bắt đầu bị rơi không?

Nói chung, cách tiếp cận bộ đệm postfix được chia sẻ có vẻ như là một cấu hình dễ vỡ để thiết lập, nhưng ít có khả năng thất bại hơn trong thời gian chạy (chuyển tiếp không khả dụng, do đó thư bị bỏ).


4

Tôi quyết định rằng cách mà container sẽ gửi thư là ghi nó vào một tệp trong một thư mục cụ thể, có thể truy cập được từ cả container và máy chủ dưới dạng "volume" Docker.

Tôi đã tạo một tập lệnh shell có tên là mailsender.sh để đọc thư từ một thư mục được chỉ định, gửi chúng đến sendmail và sau đó xóa chúng:

#!/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 sử dụng mới bắt đầu nên tôi đã tạo một tệp có tên /etc/init/mailsender.confđể biến tập lệnh này thành 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

Tôi có thể bắt đầu dịch vụ với start mailsendervà dừng nó với stop mailsender. Tôi có thể xem nhật ký của nó /var/log/upstart/mailsender.logvà dĩ nhiên tôi có thể theo dõi nó bằng tệp PID.

Bạn cần tạo /var/mailsendthư mục và sau đó làm cho nó có thể truy cập được từ bộ chứa Docker bằng cách thêm đối số -v /var/mailsend:/var/mailsendvào docker runlệnh của bạn .


Có lẽ một cái gì đó như mini_sendmail sẽ hữu ích? Nó được sử dụng trong các container, giống như một cầu nối giữa các ứng dụng bị cô lập của container và daemon máy chủ sendmail trên hệ thống máy chủ container. cyberciti.biz/tips/ nam acme.com/software/mini_sendmail
Mikl

Nếu nó gửi email đến Postfix qua SMTP, tôi không nghĩ Postfix sẽ dọn sạch email. Có lẽ nếu bạn có một MTA có cấu hình cao hơn (hoặc chúng tôi đã tìm ra cách cấu hình Postfix tốt hơn) thì nó sẽ hoạt động.
David Grayson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.