mailbox-cli.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import json
  2. import imaplib
  3. from cmd import Cmd
  4. from typing import Optional
  5. import os
  6. from time import strftime, localtime, strptime
  7. from mailbox.email import Mail
  8. from mailbox.imap import Imap
  9. class CLManager(Cmd):
  10. intro = 'Welcome to the HuanMail (IMAP).'
  11. prompt = 'HuanMail>'
  12. file = None
  13. def __init__(self):
  14. super(CLManager, self).__init__()
  15. self.imap: Optional[Imap] = None
  16. def do_load(self, path):
  17. """Load setting from file."""
  18. try:
  19. with open(path, "r", encoding="utf-8") as f:
  20. try:
  21. conf = json.load(f)
  22. imap = conf.get("imap")
  23. if imap:
  24. self.imap = Imap(
  25. user=imap["user"],
  26. passwd=imap["passwd"],
  27. host=imap.get("host", "localhost"),
  28. port=imap.get("port", 465),
  29. ssl=imap.get("ssl", True),
  30. start_ssl=imap.get("start_ssl", False)
  31. )
  32. self.imap.connect()
  33. self.imap.disconnect()
  34. self.imap.inbox = imap.get("inbox", "INBOX")
  35. mailbox = imap.get("mailbox", {})
  36. for num in imap.get("mailbox", {}):
  37. byte: str = mailbox[num]
  38. self.imap.add_mail(num, byte.encode("utf-8"))
  39. except KeyError:
  40. print("Key error.")
  41. except imaplib.IMAP4.error:
  42. print("Sorry, IMAP Authentication error. Please check your user and password.")
  43. except Exception:
  44. print("Sorry, Unknown error.")
  45. else:
  46. print("Okay.")
  47. except FileNotFoundError:
  48. print("File not fount.")
  49. except IOError:
  50. print("IO error.")
  51. def do_save(self, path):
  52. """Save setting to file."""
  53. conf = {}
  54. if self.imap:
  55. conf["imap"] = {}
  56. conf["imap"]["user"] = self.imap.user
  57. conf["imap"]["passwd"] = self.imap.passwd
  58. conf["imap"]["host"] = self.imap.host
  59. conf["imap"]["port"] = self.imap.port
  60. conf["imap"]["ssl"] = self.imap.ssl
  61. conf["imap"]["start_ssl"] = self.imap.start_ssl
  62. conf["imap"]["inbox"] = self.imap.inbox
  63. mailbox = {}
  64. for i in self.imap.mailbox:
  65. byte: bytes = i.byte
  66. mailbox[i.num] = byte.decode("utf-8")
  67. conf["imap"]["mailbox"] = mailbox
  68. try:
  69. with open(path, "w", encoding="utf-8") as f:
  70. f.write(json.dumps(conf))
  71. except FileNotFoundError:
  72. print("File not found.")
  73. except IOError:
  74. print("IO error.")
  75. else:
  76. print("Okay.")
  77. def do_login(self, arg):
  78. """Login imap server."""
  79. if len(arg) != 0:
  80. print("Bad syntax.")
  81. return
  82. user = input("User:")
  83. passwd = input("Passwd:")
  84. host = input("Host[localhost]:")
  85. port = input("Port[993]:")
  86. ssl = input("SSL[y]:")
  87. if len(host) == 0:
  88. host = "localhost"
  89. if len(port) == 0:
  90. port = 993
  91. else:
  92. try:
  93. port = int(port)
  94. except (ValueError, TypeError):
  95. print("Port must be number")
  96. return
  97. if len(ssl) == 0 or ssl == "y":
  98. ssl = True
  99. else:
  100. ssl = False
  101. print(f"""Login imap
  102. Host: {host}:{port}
  103. User: {user}
  104. Passwd: {passwd}
  105. SSL: {ssl}
  106. Sure? [Yes/No]""")
  107. if input() == "No":
  108. print("Stop.")
  109. return
  110. try:
  111. self.imap = Imap(user, passwd, host=host, port=port, ssl=ssl)
  112. self.imap.connect()
  113. self.imap.disconnect()
  114. except imaplib.IMAP4.error:
  115. print("Sorry, IMAP Authentication error. Please check your user and password.")
  116. except Exception:
  117. print("Sorry, Unknown error.")
  118. else:
  119. print("Okay.")
  120. def do_logout(self, arg):
  121. """Logout imap server."""
  122. if len(arg) != 0:
  123. print("Bad syntax.")
  124. return
  125. if input("Sure?[Yes/No]") == "No":
  126. print("Stop.")
  127. return
  128. self.imap = None
  129. print("Okay.")
  130. def do_info(self, arg):
  131. """Show imap info."""
  132. if len(arg) != 0:
  133. print("Bad syntax.")
  134. return
  135. if self.imap:
  136. print(f"""Host: {self.imap.host}:{self.imap.port}
  137. User: {self.imap.user}
  138. Passwd: {self.imap.passwd}
  139. SSL: {self.imap.ssl}
  140. MailBox: {self.imap.inbox}""")
  141. else:
  142. print("Not login.")
  143. def do_get(self, arg):
  144. """Get mail from mailbox."""
  145. if not self.imap:
  146. print("Please login first.")
  147. return
  148. if arg == "ALL":
  149. pass
  150. elif arg == "TODAY":
  151. arg = "ON " + strftime('%d-%b-%Y', localtime())
  152. else:
  153. try:
  154. arg = "ON " + strftime('%d-%b-%Y', strptime(arg, "%Y-%m-%d"))
  155. except ValueError:
  156. print("Bad syntax.")
  157. return
  158. print("Please wait...")
  159. try:
  160. self.imap.fetch_all(arg)
  161. except imaplib.IMAP4.error:
  162. print("IMAP4 error, please check setting.")
  163. else:
  164. print("Okay.")
  165. def do_show(self, arg):
  166. """Show Mail List"""
  167. try:
  168. start, step = arg.split()
  169. start = int(start)
  170. step = int(step)
  171. except (TypeError, ValueError):
  172. print("Bad syntax.")
  173. return
  174. if not self.imap:
  175. print("Please login first.")
  176. return
  177. try:
  178. mailbox = self.imap.mailbox[start:]
  179. count = 0
  180. for i in mailbox:
  181. print(f"* {i}")
  182. count += 1
  183. if count == step:
  184. break
  185. except IndexError:
  186. print("Bad index.")
  187. else:
  188. print("Okay.")
  189. def do_check(self, arg):
  190. """check --- check mail text.
  191. check save --- check mail text and save.
  192. check source --- check mail source and save.
  193. check file --- check mail file and save."""
  194. if not self.imap:
  195. print("Please login first.")
  196. return
  197. num = input("Mail number:")
  198. mail = self.imap.fetch(num)
  199. if len(arg) == 0:
  200. self.check(mail)
  201. elif arg == "save":
  202. self.check_save(mail)
  203. elif arg == "source":
  204. self.check_source(mail)
  205. elif arg == "file":
  206. self.check_file(mail)
  207. else:
  208. print(f"Bad syntax.")
  209. @staticmethod
  210. def __print_check(mail: Mail):
  211. print(f"Title: {mail.title}")
  212. print(f"From: {mail.from_addr}")
  213. print(f"Date: {mail.date}")
  214. @staticmethod
  215. def check(mail: Mail):
  216. CLManager.__print_check(mail)
  217. print(f"\n{mail.body}\n")
  218. @staticmethod
  219. def check_save(mail: Mail):
  220. CLManager.__print_check(mail)
  221. path = input("Path:")
  222. try:
  223. with open(path, "w", encoding="utf-8") as f:
  224. f.write(mail.body)
  225. except IOError:
  226. print("IO error.")
  227. else:
  228. print("Okay.")
  229. @staticmethod
  230. def check_source(mail: Mail):
  231. CLManager.__print_check(mail)
  232. path = input("Path:")
  233. try:
  234. with open(path, "wb") as f:
  235. f.write(mail.byte)
  236. except IOError:
  237. print("IO error.")
  238. else:
  239. print("Okay.")
  240. def check_file(self, mail: Mail):
  241. path = input("Path:")
  242. os.makedirs(path, exist_ok=True)
  243. try:
  244. mail.save_file(path)
  245. except IOError:
  246. print("IO error.")
  247. else:
  248. print("Okay.")
  249. def do_mailbox(self, arg):
  250. """mail show --- show all mailbox.
  251. mail setting --- select a mailbox."""
  252. if not self.imap:
  253. print("Please login first.")
  254. return
  255. if arg == "show":
  256. for i in self.imap.list():
  257. print(f"* {i}")
  258. print("Okay")
  259. elif arg == "setting":
  260. mailbox = input("Mailbox:")
  261. try:
  262. self.imap.inbox = mailbox
  263. except imaplib.IMAP4.error:
  264. print("Bad mailbox.")
  265. else:
  266. print("Okay")
  267. else:
  268. print("Bad syntax.")
  269. def do_quit(self, _):
  270. """Exit HuanMail."""
  271. print("Bye~")
  272. if self.file:
  273. self.file.close()
  274. self.file = None
  275. return True
  276. if __name__ == '__main__':
  277. manager = CLManager()
  278. try:
  279. manager.cmdloop()
  280. except KeyboardInterrupt:
  281. print("\nBye~")
  282. quit(0)