mailbox-cli.py 8.6 KB

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