Kedua-dua mod sambungan membawa mesej yang sama ke akaun relay yang sama, dan perbezaannya ialah di mana TLS bermula, bukan apa yang dihantar. Satu dibuka dalam teks jelas dan dinaik taraf dalam jalur; yang lain disulitkan dari bait pertama. Perbezaan tunggal itu menentukan apa yang akan diterima oleh dasar relay yang ketat, apa yang boleh diperhatikan oleh peranti perantaraan, dan mesej ralat mana yang akan anda habiskan satu petang membacanya. Beginilah cara saya memilih antara keduanya apabila aplikasi dalam rangkaian peribadi menyerahkan mesej kepada perkhidmatan penyerahan dalaman.

Di mana kedua-dua mod sebenarnya berbeza

Tugasnya sama dalam kedua-dua kes: mengesahkan sebagai akaun yang diluluskan, menamakan penghantar yang dibenarkan, menyenaraikan penerima, dan menunggu relay menerima tanggungjawab. Yang berubah ialah urutan operasi. Port 587 bermula sebagai sesi SMTP teks jelas, mengiklankan STARTTLS dalam respons EHLO, dan hanya dinaik taraf jika klien memintanya. Port 465 menjangka genggaman tangan TLS sebelum sebarang arahan SMTP diucapkan.

Penyerahan dan relay ialah kerja yang berbeza, sebab itu nombor port bukan tabiat yang boleh ditukar ganti. RFC 6409 menerangkan penyerahan mesej sebagai perkhidmatan tersendiri, dan RFC 8314 merangkumi varian TLS tersirat yang ditawarkan oleh kebanyakan relay moden pada 465. Jika relay anda mendokumenkan salah satu daripada keduanya, dokumentasi itu mengatasi mana-mana keutamaan yang anda peroleh daripada majikan terdahulu.

Apa yang STARTTLS pada 587 berikan kepada anda

Naik taraf berlaku dalam perbualan SMTP, jadi relay boleh mengiklankannya dan klien boleh menolak untuk meneruskan tanpanya. Dalam Python, starttls() melontar pengecualian apabila pelayan tidak menawarkan sambungan itu, yang menjadikan percubaan penurunan taraf sebagai kegagalan yang kelihatan dan bukan log masuk teks jelas yang senyap. Tingkah laku itu ialah hujah utama mod ini, dan wajar bergantung padanya secara sengaja, bukan secara kebetulan.

Tetingkap pendedahan itu kecil tetapi nyata: pertukaran EHLO awal boleh dibaca, dan tiada apa-apa sebelum naik taraf membawa kelayakan. Pada laluan peribadi antara subrangkaian aplikasi dan relay dalaman, tetingkap itu biasanya boleh diterima. Pada laluan yang anda tidak kawal, itulah sebabnya sesetengah pasukan berkeras pada mod yang lain.

Peranti pemintasan yang membuang keupayaan STARTTLS menghasilkan penyerahan yang gagal, bukan sandaran. Itulah hasil yang anda mahukan, dan ia juga cara terpantas untuk mengetahui bahawa ada sesuatu yang menulis semula SMTP pada laluan itu.

Apa yang diubah oleh TLS tersirat pada 465

Tiada langsung fasa teks jelas. Klien melakukan genggaman tangan TLS sebaik sahaja soket dibuka, mengesahkan sijil terhadap stor kepercayaannya, dan hanya selepas itu menukar EHLO, AUTH dan mesej. Tiada apa yang boleh menurunkan taraf sesi kerana tiada keadaan teks jelas untuk dirunding, dan itu menghapuskan seluruh kelas kegagalan pemintasan.

Pertukarannya ialah kebolehdiagnosan. Relay yang menjawab pada 465 dengan SMTP teks jelas, atau pengimbang beban yang menamatkan TLS dengan nama sijil yang salah, gagal pada genggaman tangan dan memberi anda ralat SSL dan bukannya ralat mel. Apabila itu berlaku, masalahnya berada di bawah aplikasi, dan sebanyak mana pun pembinaan mesej tidak akan membaikinya.

Satu fungsi penyerahan, dua pengangkutan

Kodnya hampir tidak berbeza antara mod, sebab itu pilihan harus dibuat daripada dasar relay dan bukan daripada kemudahan pustaka. Eksport tetapan dahulu, kemudian jalankan satu skrip yang memilih pengangkutan mengikut port yang dikonfigurasikan.

export SMTP_HOST=smtp.relay.internal
export SMTP_PORT=587
export SMTP_USER=svc-notify
export [email protected]
export [email protected]
export SMTP_PASSWORD="$(cat /run/secrets/smtp_password)"
import os, smtplib, ssl
from email.message import EmailMessage

ctx = ssl.create_default_context()
msg = EmailMessage()
msg["From"] = os.environ["MAIL_FROM"]
msg["To"] = os.environ["MAIL_TEST_TO"]
msg["Subject"] = "relay submission test"
msg.set_content("One authorized test message from the app.")

host = os.environ["SMTP_HOST"]
port = int(os.environ.get("SMTP_PORT", "587"))

if port == 465:
    client = smtplib.SMTP_SSL(host, port, context=ctx, timeout=15)
else:
    client = smtplib.SMTP(host, port, timeout=15)
    client.ehlo()
    client.starttls(context=ctx)
    client.ehlo()

with client:
    client.login(os.environ["SMTP_USER"], os.environ["SMTP_PASSWORD"])
    refused = client.send_message(msg)

print("refused:", refused)

create_default_context() mengesahkan rantaian dan nama hos, jadi CA peribadi mesti dipasang dalam stor kepercayaan dan bukannya dipintas dengan konteks yang tidak disahkan. send_message() memulangkan kamus penerima yang ditolak oleh relay; kamus kosong bermakna ia menerima kesemuanya. Had masa lima belas saat ialah titik permulaan, bukan nilai yang ditala untuk rangkaian anda.

Jauhkan kata laluan daripada imej dan daripada log. Rahsia yang dipasang semasa runtime dan dibaca ke dalam persekitaran adalah wajar; menggemakan persekitaran ke dalam baris log tidak wajar, dan begitu juga jejak nyahpepijat pertukaran AUTH.

Pilih mengikut dasar relay dan laluan, bukan tabiat

Tiga syarat menentukannya. Pertama, apa yang sebenarnya diiklankan oleh relay: perkhidmatan yang hanya mendengar pada 587 dengan STARTTLS tidak boleh dicapai pada 465, walau sebanyak mana anda menyukai TLS tersirat. Kedua, sama ada laluan antara aplikasi dan relay cukup dipercayai untuk menerima pertukaran EHLO yang boleh dibaca. Ketiga, sama ada sesuatu di tengah menulis semula atau memproksikan SMTP, kerana itu menentukan sama ada risiko penurunan taraf bersifat teori atau sebenar.

Apabila relay menawarkan kedua-duanya, saya mengambil 465 untuk perkhidmatan yang berjalan tanpa pengawasan dan 587 untuk perkhidmatan yang seseorang memerhati penggunaan pertama, semata-mata kerana mesej kegagalan menunjuk ke lapisan yang berbeza. Keutamaan itu milik saya dan ia bukan dasar.

Apa pun yang anda pilih, catat port, bahan kepercayaan dan domain penghantar bersama penggunaan. Kemudian hantar satu mesej ujian yang dibenarkan dan sahkan bahawa relay menerimanya, dengan menyimpan hasil penyerahan dan sebarang laporan penghantaran kemudian sebagai rekod berasingan. Penyerahan berjaya kepada relay ialah penghujung tanggungjawab aplikasi, bukan bukti bahawa mesej itu sampai ke peti masuk.

Artikel berkaitan