星期五, 7月 10, 2009

SMTP in Python - 2 (從EHLO取資訊)

由於某些SMTP server會限制信件大小,也可直接在交談中取得關於限制大小的資訊。

首先來看一下SMTP有所謂的extension,就是ESMTP,提供了強的conversation。

如何分辨server是否支援呢?

在conversation開始時,用ehlo而回傳正常資訊的,就是有支援ESMTP,

否則沒支援的話就用原本的helo來打招呼。

不同於前例使用sendmail()函式來寄送此資訊,而是要在sendmail()之前就得知檔案超過大小才行。


try:
s = smtplib.SMTP(server)
code = s.ehlo()[0]
usesesmtp = 1
if not (200 <= code <= 299):
usesesmtp = 0
code = s.helo()[0]
if not (200 <= code <= 299):
raise SMTPHeloError(code, resp)

此例中先用s.eclo()[0]來得知ehlo測試後的return code,

如果在不在正常範圍內(200~299),再改用s.helo()[0]來進行conversation。

如果真的都不行了,就raise exception來處理。


if usesesmtp and s.has_extn('size'):
print "Maximum message size is", s.esmtp_features['size']
if len(message) > int(s.esmtp_features['size']):
print "Message too large; aborting."
sys.exit(2)
s.sendmail(frmaddr, toaddrs, message)

此段會在server支援esmtp而且server有回傳max size後執行,

可以直接用s.esmtp_features['size']來取得此變數,

如果信件長度過大,則離開程式。

以下是執行結果:

cacaegg@cacabook:~/workspace/NetworkProgram/src/SMTP$ ehlo.py localhost cacaegg@localhost cacaegg@localhost
Maximum message size is 10240000
Message successfully sent to 1 recipient(s)


附件:完整python檔

SMTP in Python - 1

要寄信很簡單,只要先import smtplib即可。


import smtplib
s = smtplib.SMTP(server)
s.sendmail(fromaddr, toaddrs, message)


server:寄信的伺服器
fromaddr:寄件人
toaddrs:收件人(可以是list)
message:信件內容

再來看看關於SMTP的protocol conversation
平時smtpobj預設是關閉debug的,因此要另外打開。


try:
s = smtplib.SMTP(server)
s.set_debuglevel(1)
s.sendmail(frmaddr, toaddr, message)
except (socket.gaierror, socket.error, socket.herror, smtplib.SMTPException), e:
print " *** Your message may have not been sent!"
print e
sys.exit(1)
print "Message successfully sent to %d recipient(s)" % (len(toaddr))


多加了s.set_debuglevel(1)執行此程式就會顯示SMTP conversation messages

整支程式跑起來如下:

cacaegg@cacabook:~/workspace/NetworkProgram/src/SMTP$ debug.py localhost cacaegg@localhost cacaegg@localhost
send: 'ehlo [127.0.1.1]\r\n'
reply: '250-cacabook Hello localhost [127.0.0.1], pleased to meet you\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-EXPN\r\n'
reply: '250-VERB\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-SIZE\r\n'
reply: '250-DSN\r\n'
reply: '250-ETRN\r\n'
reply: '250-AUTH DIGEST-MD5 CRAM-MD5\r\n'
reply: '250-DELIVERBY\r\n'
reply: '250 HELP\r\n'
reply: retcode (250); Msg: cacabook Hello localhost [127.0.0.1], pleased to meet you
ENHANCEDSTATUSCODES
PIPELINING
EXPN
VERB
8BITMIME
SIZE
DSN
ETRN
AUTH DIGEST-MD5 CRAM-MD5
DELIVERBY
HELP
send: 'mail FROM: size=155\r\n'
reply: '250 2.1.0 ... Sender ok\r\n'
reply: retcode (250); Msg: 2.1.0 ... Sender ok
send: 'rcpt TO:\r\n'
reply: '250 2.1.5 ... Recipient ok\r\n'
reply: retcode (250); Msg: 2.1.5 ... Recipient ok
send: 'data\r\n'
reply: '354 Enter mail, end with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter mail, end with "." on a line by itself
data: (354, 'Enter mail, end with "." on a line by itself')
send: 'To: cacaegg@localhost\r\nFrom: cacaegg@localhost\r\nSubject: Test Message from simple.py\r\n\r\nHello,\r\n\r\nThis is a test message sent to you fromsimple.py and smtplib.\r\n.\r\n'
reply: '250 2.0.0 n6A2nMKj013583 Message accepted for delivery\r\n'
reply: retcode (250); Msg: 2.0.0 n6A2nMKj013583 Message accepted for delivery
data: (250, '2.0.0 n6A2nMKj013583 Message accepted for delivery')
Message successfully sent to 1 recipient(s)


最後簡單註解模擬一下SMTP conversation protocol ([]為註解)

send: 'ehlo [127.0.1.1]\r\n'
[client:server 你好,我是127.0.1.1]

reply: '250-ENHANCEDSTATUSCODES\r\n'
...bala
reply: '250 HELP\r\n'
reply: retcode (250); Msg: cacabook Hello localhost [127.0.0.1], pleased to meet you
[server: cacabook 你好,我有這些提供這些服務的選項,來參考看看]

ENHANCEDSTATUSCODES
...bala
HELP
[client murmur:那我就選這些 bala...]

send: 'mail FROM: size=155\r\n'
[client: 這封信是從cacaegg@localhost來的,大小是155 byte]

reply: '250 2.1.0 ... Sender ok\r\n'
reply: retcode (250); Msg: 2.1.0 ... Sender ok
[server: 寄件人... 好的]

send: 'rcpt TO:\r\n'
[client: 我要寄給cacaegg@localhost]

reply: '250 2.1.5 ... Recipient ok\r\n'
reply: retcode (250); Msg: 2.1.5 ... Recipient ok
[server: 收件人... 好的]

send: 'data\r\n'
[client: 我要開始說信件內容囉]

reply: '354 Enter mail, end with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter mail, end with "." on a line by itself
[server: 請說!說完以後就在打上.我就知道你說完了!]

data: (354, 'Enter mail, end with "." on a line by itself')
send: 'To: cacaegg@localhost\r\nFrom: cacaegg@localhost\r\nSubject: Test Message from simple.py\r\n\r\nHello,\r\n\r\nThis is a test message sent to you fromsimple.py and smtplib.\r\n.\r\n'
[client: 我的內容是balabala....]
[client: .]

reply: '250 2.0.0 n6A2nMKj013583 Message accepted for delivery\r\n'
reply: retcode (250); Msg: 2.0.0 n6A2nMKj013583 Message accepted for delivery
[server: 好的,我會幫你寄送!]

其實server說好也不一定代表信就會寄出,可能原因有很多種,舉些例子
1.server判斷你是spam,就不幫你寄信了
2.server只是轉寄站,還要繼續轉寄到其他的mail server,可能到最後還是無法到達。
這情況通常會有bounce message

附件:為整支程式,可以抓下來直接跑!

Text-based mail client

想在ubuntu的console下用文字收信,有個老牌的軟體pine

只是apt中好像把他停用了,找到了另外一個alpine

就幾乎跟pine一模一樣了。


cacaegg@cacabook:~$ sudo apt-get install alpine
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
libswfdec-0.8-0
Use 'apt-get autoremove' to remove them.
The following NEW packages will be installed:
alpine
0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
Need to get 2913kB of archives.
After this operation, 6636kB of additional disk space will be used.
Get:1 http://tw.archive.ubuntu.com jaunty/universe alpine 2.00+dfsg-2ubuntu2 [2913kB]
Fetched 2913kB in 2s (976kB/s)
Selecting previously deselected package alpine.
(Reading database ... 259353 files and directories currently installed.)
Unpacking alpine (from .../alpine_2.00+dfsg-2ubuntu2_i386.deb) ...
Processing triggers for man-db ...
Setting up alpine (2.00+dfsg-2ubuntu2) ...
cacaegg@cacabook:~$ alpine

就可以使用囉!

星期五, 7月 03, 2009

KDE 下鍵盤失效

在打完帳號密碼,登入以後

鍵盤通通都失效了,只剩滑鼠可以使用

加上許多icon都不見了(例如shutdown, logout)

乾脆直接把KDE的設定全部刪掉

在打帳號密碼時,進入console login

%rm -r ~/.kde

就可以了

星期二, 6月 30, 2009

Basic Parse HTML

Python中利用HTMLParser Module來處理HTML格式。

from HTMLParser import HTMLParser

class MyParser(HTMLParser):
def handle_starttag(self, tag, attrs):
# code to process start tag

def handle_data(self, data):
# code to process data between start and end tag

def handle_endtag(self, tag):
# code to process end tag

fd = open(sys.argv[1])
mp = MyParser()
mp.feed(fd.read())



mp.feed會依據處理到的資料呼叫對應的handle function,如此就可以處理HTML文件了。