|
@@ -0,0 +1,380 @@
|
|
|
+import smtplib
|
|
|
+import json
|
|
|
+from cmd import Cmd
|
|
|
+from typing import Optional
|
|
|
+
|
|
|
+from sender.email import Email
|
|
|
+from sender.smtp import Sender
|
|
|
+
|
|
|
+
|
|
|
+class CLManager(Cmd):
|
|
|
+ intro = 'Welcome to the HuanMail (SMTP).'
|
|
|
+ prompt = 'HuanMail>'
|
|
|
+ file = None
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ super(CLManager, self).__init__()
|
|
|
+ self.sender: Optional[Sender] = None
|
|
|
+ self.email: Optional[Email] = None
|
|
|
+
|
|
|
+ def do_load(self, path):
|
|
|
+ """Load setting from file."""
|
|
|
+
|
|
|
+ try:
|
|
|
+ with open(path, "r", encoding="utf-8") as f:
|
|
|
+ try:
|
|
|
+ conf = json.load(f)
|
|
|
+ sender = conf.get("sender")
|
|
|
+ if sender:
|
|
|
+ self.sender = Sender(
|
|
|
+ user=sender["user"],
|
|
|
+ passwd=sender["passwd"],
|
|
|
+ host=sender.get("host", "localhost"),
|
|
|
+ port=sender.get("port", 465),
|
|
|
+ debug=sender.get("debug", False),
|
|
|
+ ssl=sender.get("ssl", True),
|
|
|
+ start_ssl=sender.get("start_ssl", False)
|
|
|
+ )
|
|
|
+
|
|
|
+ email = conf.get("email", {})
|
|
|
+ if email:
|
|
|
+ self.email = Email(
|
|
|
+ from_addr=(email["from_name"], email["from_addr"]),
|
|
|
+ subject=input("Title:")
|
|
|
+ )
|
|
|
+ except smtplib.SMTPAuthenticationError:
|
|
|
+ print("Sorry, SMTP Authentication error. Please check your user and password.")
|
|
|
+ except smtplib.SMTPException:
|
|
|
+ print("Sorry, SMTP error.")
|
|
|
+ except KeyError:
|
|
|
+ print("Key error.")
|
|
|
+ except Exception:
|
|
|
+ print("Sorry, Unknown error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+ except FileNotFoundError:
|
|
|
+ print("File not fount.")
|
|
|
+ except IOError:
|
|
|
+ print("IO error.")
|
|
|
+
|
|
|
+ def do_save(self, arg):
|
|
|
+ """Save setting to file."""
|
|
|
+
|
|
|
+ conf = {}
|
|
|
+ if self.sender:
|
|
|
+ conf["sender"] = {}
|
|
|
+ conf["sender"]["user"] = self.sender.user
|
|
|
+ conf["sender"]["passwd"] = self.sender.passwd
|
|
|
+ conf["sender"]["host"] = self.sender.host
|
|
|
+ conf["sender"]["port"] = self.sender.port
|
|
|
+ conf["sender"]["debug"] = self.sender.debug
|
|
|
+ conf["sender"]["ssl"] = self.sender.ssl
|
|
|
+ conf["sender"]["start_ssl"] = self.sender.start_ssl
|
|
|
+
|
|
|
+ if self.email:
|
|
|
+ conf["email"] = {}
|
|
|
+ conf["email"]["from_name"], conf["email"]["from_addr"] = self.email.from_addr
|
|
|
+
|
|
|
+ try:
|
|
|
+ with open(arg, "w", encoding="utf-8") as f:
|
|
|
+ f.write(json.dumps(conf))
|
|
|
+ except FileNotFoundError:
|
|
|
+ print("File not found.")
|
|
|
+ except IOError:
|
|
|
+ print("IO error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def do_sender(self, arg):
|
|
|
+ """sender setting -- setting the sender.
|
|
|
+sender show -- show sender info.
|
|
|
+sender delete -- delete the sender."""
|
|
|
+
|
|
|
+ if arg == "setting":
|
|
|
+ self.sender_setting()
|
|
|
+ elif arg == "show":
|
|
|
+ self.sender_show()
|
|
|
+ elif arg == "delete":
|
|
|
+ self.sender_delete()
|
|
|
+ else:
|
|
|
+ print(f"Bad syntax.")
|
|
|
+ return
|
|
|
+
|
|
|
+ def sender_show(self):
|
|
|
+ print(f"""Host: {self.sender.host}:{self.sender.port}
|
|
|
+User: {self.sender.user}
|
|
|
+Passwd: {self.sender.passwd}""")
|
|
|
+
|
|
|
+ def sender_setting(self):
|
|
|
+ user = input("User:")
|
|
|
+ passwd = input("Passwd:")
|
|
|
+ host = input("Host[localhost]:")
|
|
|
+ port = input("Port[465]:")
|
|
|
+ debug = input("Debug[n]:")
|
|
|
+ ssl = input("SSL[y]:")
|
|
|
+
|
|
|
+ if len(host) == 0:
|
|
|
+ host = "localhost"
|
|
|
+
|
|
|
+ if len(port) == 0:
|
|
|
+ port = 465
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ port = int(port)
|
|
|
+ except (ValueError, TypeError):
|
|
|
+ print("Port must be number")
|
|
|
+ return
|
|
|
+
|
|
|
+ if len(debug) == 0 or debug == "n":
|
|
|
+ debug = False
|
|
|
+ else:
|
|
|
+ debug = True
|
|
|
+
|
|
|
+ if len(ssl) == 0 or ssl == "y":
|
|
|
+ ssl = True
|
|
|
+ else:
|
|
|
+ ssl = False
|
|
|
+
|
|
|
+ print(f"""Setting sender
|
|
|
+Host: {host}:{port}
|
|
|
+User: {user}
|
|
|
+Passwd: {passwd}
|
|
|
+Debug: {debug}
|
|
|
+SSL: {ssl}
|
|
|
+Sure? [Yes/No]""")
|
|
|
+
|
|
|
+ if input() == "No":
|
|
|
+ print("Stop.")
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ self.sender = Sender(user, passwd, host=host, port=port, debug=debug, ssl=ssl)
|
|
|
+ except smtplib.SMTPAuthenticationError:
|
|
|
+ print("Sorry, SMTP Authentication error. Please check your user and password.")
|
|
|
+ except smtplib.SMTPException:
|
|
|
+ print("Sorry, SMTP error.")
|
|
|
+ except Exception:
|
|
|
+ print("Sorry, Unknown error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def sender_delete(self):
|
|
|
+ if input("Sure?[Yes/No]") == "No":
|
|
|
+ print("Stop.")
|
|
|
+ return
|
|
|
+
|
|
|
+ self.sender = None
|
|
|
+ print("Sender has been delete.")
|
|
|
+
|
|
|
+ def do_email(self, arg):
|
|
|
+ """email new -- create a new email.
|
|
|
+email delete -- delete the email.
|
|
|
+email text -- add test to email.
|
|
|
+email text-file -- add text from file to email.
|
|
|
+email html -- add html to email.
|
|
|
+email html-file -- add html from file to email.
|
|
|
+email file -- add a file to email.
|
|
|
+email show -- show the email info."""
|
|
|
+
|
|
|
+ if arg == "new":
|
|
|
+ self.email_new()
|
|
|
+ else:
|
|
|
+ if not self.email:
|
|
|
+ print("Please create email first.")
|
|
|
+ return
|
|
|
+
|
|
|
+ if arg == "delete":
|
|
|
+ self.email_delete()
|
|
|
+ elif arg == "text":
|
|
|
+ self.email_text()
|
|
|
+ elif arg == "text-file":
|
|
|
+ self.email_text_file()
|
|
|
+ elif arg == "html":
|
|
|
+ self.email_html()
|
|
|
+ elif arg == "html-file":
|
|
|
+ self.email_html_file()
|
|
|
+ elif arg == "file":
|
|
|
+ self.email_file()
|
|
|
+ elif arg == "show":
|
|
|
+ self.email_show()
|
|
|
+ else:
|
|
|
+ print(f"Bad syntax.")
|
|
|
+
|
|
|
+ def email_new(self):
|
|
|
+ if self.email and input("Sure?[Yes/No]") == "No":
|
|
|
+ print("Stop.")
|
|
|
+ return
|
|
|
+
|
|
|
+ from_addr = input("From email address:")
|
|
|
+ from_name = input("From name:")
|
|
|
+ subject = input("Title:")
|
|
|
+
|
|
|
+ self.email = Email((from_name, from_addr), subject)
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_delete(self):
|
|
|
+ if input("Sure?[Yes/No]") == "No":
|
|
|
+ print("Stop.")
|
|
|
+ return
|
|
|
+
|
|
|
+ self.email = None
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_text(self):
|
|
|
+ self.email.add_text(self.get_text())
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_text_file(self):
|
|
|
+ try:
|
|
|
+ self.email.add_text_from_file(input("Path:"))
|
|
|
+ except FileNotFoundError:
|
|
|
+ print("File not fount.")
|
|
|
+ except IOError:
|
|
|
+ print("IO error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_html(self):
|
|
|
+ self.email.add_html(self.get_text())
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_html_file(self):
|
|
|
+ try:
|
|
|
+ self.email.add_html_from_file(input("Path:"))
|
|
|
+ except FileNotFoundError:
|
|
|
+ print("File not fount.")
|
|
|
+ except IOError:
|
|
|
+ print("IO error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_file(self):
|
|
|
+ filename = input("Filename:")
|
|
|
+ path = input("Path:")
|
|
|
+ try:
|
|
|
+ self.email.add_from_file(filename, path)
|
|
|
+ except FileNotFoundError:
|
|
|
+ print("File not fount.")
|
|
|
+ except IOError:
|
|
|
+ print("IO error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def email_show(self):
|
|
|
+ print(f"From: {self.email.from_addr[0]} <{self.email.from_addr[1]}>")
|
|
|
+ print(f"Title: {self.email.subject}")
|
|
|
+
|
|
|
+ print("* Text: ")
|
|
|
+ for i in self.email.text:
|
|
|
+ print(i)
|
|
|
+ print("-" * 5)
|
|
|
+
|
|
|
+ print("* HTML: ")
|
|
|
+ for i in self.email.html:
|
|
|
+ print(i)
|
|
|
+ print("-" * 5)
|
|
|
+
|
|
|
+ print("* File: ")
|
|
|
+ for i in self.email.file:
|
|
|
+ print(i[0])
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def get_text():
|
|
|
+ end = input("End:")
|
|
|
+ text = ""
|
|
|
+ while True:
|
|
|
+ get = input(">>> ")
|
|
|
+ if get == end:
|
|
|
+ return text[:-1]
|
|
|
+ text += get + "\n"
|
|
|
+
|
|
|
+ def do_rc(self, arg):
|
|
|
+ """rc add-to -- add recipient.
|
|
|
+rc add-cc -- add CC person.
|
|
|
+rc add-bcc -- add BCC person.
|
|
|
+rc show -- show recipient, CC person, BCC person."""
|
|
|
+
|
|
|
+ if not self.email:
|
|
|
+ print("Please create email first.")
|
|
|
+ return
|
|
|
+
|
|
|
+ if arg == "add-to":
|
|
|
+ self.rc_add_to()
|
|
|
+ elif arg == "add-cc":
|
|
|
+ self.rc_add_cc()
|
|
|
+ elif arg == "add-bcc":
|
|
|
+ self.rc_add_bcc()
|
|
|
+ elif arg == "show":
|
|
|
+ self.rc_show()
|
|
|
+ else:
|
|
|
+ print(f"Bad syntax.")
|
|
|
+
|
|
|
+ def rc_add_to(self):
|
|
|
+ name = input("Name:")
|
|
|
+ email = input("Email:")
|
|
|
+ self.email.add_to_addr(name, email)
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def rc_add_cc(self):
|
|
|
+ name = input("Name:")
|
|
|
+ email = input("Email:")
|
|
|
+ self.email.add_cc_addr(name, email)
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def rc_add_bcc(self):
|
|
|
+ name = input("Name:")
|
|
|
+ email = input("Email:")
|
|
|
+ self.email.add_bcc_addr(name, email)
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def rc_show(self):
|
|
|
+ print("* Recipient:")
|
|
|
+ for name, email in self.email.to_addr:
|
|
|
+ print(f"{name} <{email}>")
|
|
|
+
|
|
|
+ print("* CC Person:")
|
|
|
+ for name, email in self.email.cc_addr:
|
|
|
+ print(f"{name} <{email}>")
|
|
|
+
|
|
|
+ print("* BCC Person:")
|
|
|
+ for name, email in self.email.bcc_addr:
|
|
|
+ print(f"{name} <{email}>")
|
|
|
+
|
|
|
+ def do_send(self, arg):
|
|
|
+ """Send email"""
|
|
|
+ if len(arg) != 0:
|
|
|
+ print(f"Bad syntax for '{arg}'.")
|
|
|
+ return
|
|
|
+
|
|
|
+ if not self.email:
|
|
|
+ print("Please create email first.")
|
|
|
+ return
|
|
|
+
|
|
|
+ if not self.sender:
|
|
|
+ print("Please create sender first.")
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ self.sender.send(self.email)
|
|
|
+ except smtplib.SMTPException:
|
|
|
+ print("SMTP error.")
|
|
|
+ else:
|
|
|
+ print("Okay.")
|
|
|
+
|
|
|
+ def do_quit(self, _):
|
|
|
+ """Exit HuanMail."""
|
|
|
+
|
|
|
+ print("Bye~")
|
|
|
+ if self.file:
|
|
|
+ self.file.close()
|
|
|
+ self.file = None
|
|
|
+ return True
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ manager = CLManager()
|
|
|
+ try:
|
|
|
+ manager.cmdloop()
|
|
|
+ except KeyboardInterrupt:
|
|
|
+ print("\nBye~")
|
|
|
+ quit(0)
|