Rename SecureInbox to SecureMail, since it is used for not only ingoing but also...
[easyotp.git] / SecureMail.py
blobd6533c629bad5ecaf33bc642ca5f8d52bbf789e0
1 #!/bin/env python
2 # Created:20080603
3 # By Jeff Connelly
5 # Communicate with mail servers
7 import imaplib
8 import smtplib
9 import getpass
10 import email
12 class SecureMail(object):
13 def __init__(self, username=None, password=None):
14 """Prompt for login and password, or using stored values if possible, then login."""
16 if username is None:
17 try:
18 username = file(".otplogin").read().strip()
19 except:
20 username = raw_input("Username: ")
22 if password is None:
23 try:
24 password = file(".otppass").read().strip()
25 except:
26 password = getpass.getpass()
28 return self.login(username, password)
31 def login(self, username, password):
32 """Login to a Gmail account, IMAP and SMTP server, with login and password."""
34 # IMAP SSL for incoming messages
35 self.mail_in = imaplib.IMAP4_SSL("imap.gmail.com", 993)
37 self.username = username
39 try:
40 typ, data = self.mail_in.login(username, password)
41 except imaplib:
42 raise "Login failure: %s" % (sys.exc_info(),)
43 else:
44 assert typ == "OK", "imap login returned: %s %s" % (status, message)
45 print "Logged in:", typ, data
47 # Always have "Secure" mailbox selected
48 typ, num_msgs = self.mail_in.select(mailbox="Secure")
49 if typ != "OK":
50 raise ("imap select failure: %s %s" % (typ, num_msgs) +
51 "The 'Secure' tag doesn't exist. Tag some of your EMOTP messages" +
52 "using a new label, named 'Secure'")
54 # Outgoing mail, SMTP server
55 self.mail_out = smtplib.SMTP("smtp.gmail.com", 25)
56 ret = self.mail_out.ehlo()
57 assert ret[0] == 250, "SMTP server EHLO failed: %s" % (ret,)
59 ret = self.mail_out.starttls()
60 assert ret[0] == 220, "SMTP server STARTTLS failed: %s" % (ret,)
62 ret = self.mail_out.ehlo()
63 assert ret[0] == 250, "SMTP server EHLO over TLS failed: %s" % (ret,)
65 ret = self.mail_out.noop()
66 assert ret[0] == 250, "SMTP server NOOP failed: %s" % (ret,)
68 ret = self.mail_out.login(username, password)
69 assert ret[0] == 235, "SMTP server login failed: %s" % (ret,)
70 print "Logged in to SMTP server: %s" % (ret,)
72 def get_messages(self):
73 msgs = []
75 try:
76 typ, all_msgs_string = self.mail_in.search(None, 'ALL')
77 except imaplib.error, e:
78 raise "imap search failed: %s" % (e,)
80 all_msgs = all_msgs_string[0].split()
81 for num in all_msgs:
82 typ, body = self.mail_in.fetch(num, "(BODY[])")
83 msg = email.message_from_string(body[0][1])
85 body = str(msg.get_payload())
86 subject = msg.get("Subject")
87 sender = msg.get("From")
88 id = msg.get("Message-ID")
90 #print 'Message %s\n%s\n' % (num, data[0][1])
91 if "--EMOTP_BEGIN--" not in body:
92 continue
94 msgs.append({"body": body,
95 "subject": subject,
96 "sender": sender,
97 "id": id,
98 "num": num})
100 return msgs
102 def __iter__(self):
103 """Fetch messages from server."""
104 self.msgs = self.get_messages()
105 return iter(self.msgs)
107 def __getitem__(self, k):
108 """Lookup a message of a given number. Messages
109 must have been previous fetched from server up by __iter__"""
110 return self.msgs[k]
112 def send(self, to, subject, body):
113 from_address = "%s@gmail.com" % (self.username,)
114 return self.mail_out.sendmail(from_address,
115 [to],
116 "\r\n".join([
117 "From: %s" % (from_address,),
118 "To: %s" % (to,),
119 "Subject: %s" % (subject,),
121 body]))
123 def __del__(self):
124 self.mail_in.close()
125 self.mail_in.logout()
126 self.mail_out.quit()
128 def main():
129 ms = SecureMail("shellreef", getpass.getpass())
131 for m in ms.get_messages():
132 print m["sender"], m["subject"]
134 if __name__ == "__main__":
135 main()