1. 程式人生 > >Python發送郵件:smtplib、sendmail

Python發送郵件:smtplib、sendmail

postfix prot 找到 serve qmail 問題 配置文件 什麽 分享圖片

本地Ubuntu 18.04,本地Python 3.6.5,

阿裏雲Ubuntu 16.04,阿裏雲Python 3.5.2,

smtplib,sendmail 8.15.2,

今天,打算實現通過電子郵件發送 註冊用戶激活功能,原以為一天是夠夠的了,誰知,踩到 坑了:一個軟件坑,一個ECS坑。

早上一來,便按照教程Python SMTP發送郵件做測試,很簡單,使用smtplib模塊 在 安裝了sendmail的電腦上就可以執行郵件發送功能了。

只是,sendmail是什麽?先用起來再說!

拷貝了教程中第一段代碼,並更改了其中的sender和receivers,如下:

# -*- coding: UTF-8 -*-
‘‘‘ Created on 2018年8月15日 @author: log ‘‘‘ import smtplib from email.mime.text import MIMEText from email.header import Header import traceback sender = ‘[email protected]‘ receivers = [‘[email protected]‘, ‘[email protected]‘] # 三個參數 message = MIMEText(來自Python smtplib模塊發送的測試郵件...請勿回復(Ubuntu),
plain, utf-8) message[From] = Header(測試郵件, utf-8) message[To] = Header(自己, utf-8) subject = Python smtplib郵件發送測試 message[Subject] = Header(subject, utf-8) try: smtpObj = smtplib.SMTP(localhost) smtpObj.sendmail(sender, receivers, message.as_string()) print(沒有異常發生,郵件發送成功...
) except: traceback.print_exc() print(Error: 郵件發送失敗)

sendmail安裝

本地和阿裏雲Ubuntu中都沒有安裝sendmail,使用下面的命令安裝:

sudo apt install sendmail

sendmail安裝完畢,開始測試程序。

sendmail安裝位置查詢:

$ whereis sendmail
sendmail: /usr/sbin/sendmail /usr/lib/sendmail /usr/share/sendmail /usr/share/man/man8/sendmail.8.gz

配置文件位於/etc/mail/目錄中,文件很多,挺復雜的。開始遇到問題時,修改過其中的sendmail.mc、sendmail.cf,後來才知道,其實不需要更改的。

日誌文件位於/var/log/目錄中,mail.log、mail.err,後者為錯誤記錄文件,查看兩個信息、定位問題,很關鍵。

技術分享圖片

技術分享圖片

技術分享圖片

常用命令mail、mailq,mail查看 接收到的郵件,mailq查看 待發送郵件。

更多說明:

mail命令可以查看收到的郵件,今天在本地測試時,有收到一些郵件,具體操作,還需看起文檔、資料(當然,自己發送的郵件是被當作垃圾郵件的spam)。

技術分享圖片

mailq的待發送郵件存在於/var/spool/mqueue-client、/var/spool/mqueue兩個目錄中,直接刪除其中的文件,即可刪除所有待發送郵件,但要註意,裏面存儲的可不一定是自己這個用戶的待發送郵件,更好的方法是使用一個叫做postsuper(需要安裝postfix)命令按用戶刪除——孤沒有安裝它,直接去目錄中刪除的。

測試程序

因為有本地Ubuntu,所以,將上面的代碼拷貝到本地Ubuntu中運行——virtualenv中,Python 3.6.5。

結果,遇到了第一個問題

smtplib.SMTPRecipientsRefused: {‘[email protected]‘: (553, b‘5.1.8 <[email protected]>... Domain of sender address [email protected] does not exist‘), ‘[email protected]‘: (553, b‘5.1.8 <[email protected]>... Domain of sender address [email protected] does not exist‘)}

發送者sender的域名[email protected]不存在!

更改sender為sender = ‘[email protected]‘,測試程序,仍然失敗!

更改sender為[email protected],receivers為[‘[email protected]‘],想實現從[email protected]發送郵件到[email protected],當然,失敗了!的確也應該失敗,都不登錄就想法郵件?不可能的!

日誌分析

在sendmail的日誌文件中找到一些記錄:

My unqualified host name (myhostname) unknown; sleeping for retry

unable to qualify my own domain name (myhostname) -- using short name

--

w7F2vjwT000424: to=<[email protected]>, delay=00:08:00, xdelay=00:08:00, mailer=esmtp, pri=120327, relay=mx1.qq.com. [183.57.48.35], dsn=4.0.0, stat=Deferred: Connection timed out with mx1.qq.com.

下面是阿裏雲上測試的日誌記錄:

sm-mta[1076]: w7F3lErF001076: from=<from@myhostname>, size=327, class="0", nrcpts=2, msgid=<201808150347.w7F3lErF001076@myhostname>, proto=ESMTP, daemon=MTA-v4, relay=localhost [127.0.0.1]

sm-mta[1118]: w7F3nI5V001118: from=<from@localhost>, size=327, class="0", nrcpts=2, msgid=<201808150349.w7F3nI5V001118@myhostname>, proto=ESMTP, daemon=MTA-v4, relay=localhost [127.0.0.1]

sm-mta[1134]: w7F3p4ua001134: from=<myqqmail@qq.com>, size=327, class="0", nrcpts=1, msgid=<201808150351.w7F3p4ua001134@myhostname>, proto=ESMTP, daemon=MTA-v4, relay=localhost [127.0.0.1]

--

My unqualified host name (myhostname) unknown; sleeping for retry

unable to qualify my own domain name (myhostname) -- using short name

P.S.一個上午就這麽過去了,哎呀,

想了一下,本地和阿裏雲都有下面的日誌記錄:

My unqualified host name (myhostname) unknown; sleeping for retry

unable to qualify my own domain name (myhostname) -- using short name

那麽,先解決這個問題先。

解決方案:更改/etc/hosts文件

怎麽修改?

阿裏雲ECS 更改前 hosts文件中存在下面的語句:

ipv4_addr myhostname myhostname

更改後:

ipv4_addr myhostname domain.name.com

將第二個更改為域名即可,當然,這個域名應該不能使qq.com、163.com等吧?這裏孤不清楚,還需dig。

註意:在修改之後,ECS重啟後會在更改後的配置下面添加原來的ipv4_addr myhostname myhostname,即出現兩行。為何如此呢?

本地安裝在虛擬機中的Ubuntu的hosts中部分配置:

127.0.0.1 localhost

127.0.1.1 localhost

更改後:

127.0.0.1 localhost

127.0.1.1 localhost some_name.me

為何添加一個somename.me呢?這個some_name.me是一個域名,還嘗試了配置為自己購買的域名,以及其它域名,在本地測試時都成功發送了郵件。

對了,怎麽不配置在第一行127.0.0.1後面呢?或許可以,未嘗試,需dig,

P.S.都是Ubuntu,版本不同,但hosts文件的差別挺大的呢!

說明:更改hosts文件後,sendmail的軟件坑就算解決了,沒有上面的“unknown; sleeping for retry...unable to qualify my own domain name”錯誤提示了,下面ECS的坑緊接著就來了,而這個ECS的坑的名字叫做阿裏雲默認封禁TCP 25端口出方向的訪問流量

P.S.下面的測試都是在修改了hosts文件後進行的測試。

大錯特錯的是:自己首先用阿裏雲進行了測試,結果,郵件一直發送失敗。結果就是,mailq裏面有越來越多的 待發送郵件,進程裏面有很多目的主機端口為25的狀態為SYN_SENT的連接存在

$ mailq
MSP Queue status...
/var/spool/mqueue-client is empty
                Total requests: 0
MTA Queue status...
                /var/spool/mqueue (18 requests)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
w7F6USWQ002743*       4 Wed Aug 15 14:30 <[email protected]>
                                         <[email protected]>
w7F6N0hd002648*       4 Wed Aug 15 14:23 <[email protected]>
                 (Deferred: Connection timed out with mx1.qq.com.)
                                         <[email protected]>
w7F1Z5w4032186*     102 Wed Aug 15 09:35 <[email protected]>
                 (Deferred: Connection timed out with 163mx00.mxmail.netease.c)
                                         <[email protected]>
w7F1VIFh032131      102 Wed Aug 15 09:31 <[email protected]>
                 (Deferred: Connection timed out with 163mx00.mxmail.netease.c)
                                         <[email protected]>

netstat -ano | grep :25:郵件發送成後,只會存在一個的,即狀態為LISTEN那個進程,這些SYN_SENT表示在重發mailq中的 待發送郵件。

$ netstat -ano | grep :25
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      off (0.00/0/0)
tcp        0      1 172.18.232.21:45698     220.181.14.145:25       SYN_SENT    on (12.06/4/0)
tcp        0      1 172.18.232.21:57766     220.181.14.144:25       SYN_SENT    on (59.02/6/0)
tcp        0      1 172.18.232.21:39008     123.125.50.139:25       SYN_SENT    on (57.35/6/0)
tcp        0      1 172.18.232.21:36952     14.17.41.170:25         SYN_SENT    on (3.37/4/0)
tcp6       0      1 172.18.232.21:40978     220.181.14.135:25       SYN_SENT    on (5.96/5/0)
tcp6       0      1 172.18.232.21:52616     220.181.14.149:25       SYN_SENT    on (21.32/6/0)

就不多說了,此問題由ECS坑造成的,還好,至少本地郵件發送成功了,否則,今天一定要郁悶到吐血啊!

不過自己定位問題、解決問題的效率挺低的,不夠專註,多次被其它東西幹擾!

展示下成果——全來自本地Ubuntu:

-163.com收到的郵件

技術分享圖片

發件人域名為log-u18.me

技術分享圖片

發件人域名為自己購買的域名

技術分享圖片

-qq.com收到的郵件

QQ郵箱會屏蔽這些本地Ubuntu發來的郵件,需要 首頁--我的信息--自助查詢 中將它們 取回才可以。

技術分享圖片

上圖紫色方框中的郵件很有意思,內容入下圖——發件人就是簡單的log,後面居然沒有跟著域名!

顛覆了自己的認知啊!

不過,在網易郵箱中沒有發現這封郵件!

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

總結

阿裏雲ECS的這個坑可以申請使用25端口來提供郵件服務,據說只要1天審核時間;

但自己不準備這麽做了,現在有網易郵箱、QQ郵箱,而且都可以開啟SMTP服務,那麽就是使用它們的服務器來發送郵件嘛,個人網站,發送的郵件又不多;

所以,還需要用註冊手機開發網易郵箱、QQ郵箱的SMTP服務才可以。

至今,自己對sendmail所知甚少,怎麽配置、怎麽開發的、源碼分析,估計是不會做更多研究了,安裝了,就可以了。

至於Python標準庫中的其它一些郵件操作庫,暫時也是沒有精時去了解研究了:

The Python Standard Library
https://docs.python.org/3.5/library/index.html
21. Internet Protocols and Support
21.14. poplib — POP3 protocol client
21.15. imaplib — IMAP4 protocol client
21.17. smtplib — SMTP protocol client
21.18. smtpd — SMTP Server

19. Internet Data Handling
19.1. email — An email and MIME handling package
19.3. mailcap — Mailcap file handling
19.4. mailbox — Manipulate mailboxes in various formats

把握重點,用到多少,就學多少,就醬!別擔心沒學到的會怎樣怎樣!沒學到,可是,自己還是把系統搭建起來了啊!

哈哈哈哈~孤的系統,快快上線吧!~

參考資料:

Python SMTP發送郵件

The Python 3.5 Standard Library

smtplib — SMTP protocol client

阿裏雲ECS: TCP 25端口解封申請

Sendmail Open Source

sendmail安裝使用

linux之發送郵件--sendmail服務配置

TCP協議端口狀態說明 by jessezeng

sendmail 報錯:unable to qualify my own domain name

Python發送郵件:smtplib、sendmail