user.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. from sender.smtp import Sender
  2. from sender.email import Email
  3. from mailbox.imap import Imap
  4. from mailbox.email import Mail
  5. from .db import redis
  6. from .configure import conf
  7. from flask_login import UserMixin
  8. from threading import Thread
  9. from .logger import Logger
  10. EXPIRE = conf["REDIS_EXPIRE"]
  11. class User(UserMixin):
  12. def __init__(self, username, passwd=None):
  13. self.id = username
  14. self.username = username
  15. if passwd:
  16. redis.hmset(f"user:{username}", {"passwd": passwd})
  17. @property
  18. def smtp_address(self):
  19. return conf["SMTP_USERNAME"].format(self.username)
  20. def check_login(self):
  21. imap = Imap(user=conf["IMAP_USERNAME"].format(self.username),
  22. passwd=conf["IMAP_PASSWD"].format(self.passwd),
  23. host=conf["IMAP_HOST"],
  24. port=conf["IMAP_PORT"],
  25. ssl=conf["IMAP_SSL"],
  26. start_ssl=conf["IMAP_START_SSL"])
  27. sender = Sender(user=conf["SMTP_USERNAME"].format(self.username),
  28. passwd=conf["SMTP_PASSWD"].format(self.passwd),
  29. host=conf["SMTP_HOST"],
  30. port=conf["SMTP_PORT"],
  31. ssl=conf["SMTP_SSL"],
  32. start_ssl=conf["SMTP_START_SSL"],
  33. debug=False)
  34. if not imap.check_login():
  35. Logger.print_user_opt_success_log("imap check login")
  36. return False
  37. if not sender.check_login():
  38. Logger.print_user_opt_success_log("smtp check login")
  39. return False
  40. Logger.print_user_opt_success_log("check login")
  41. return True
  42. @property
  43. def info(self):
  44. return redis.hgetall(f"user:{self.username}")
  45. @property
  46. def passwd(self):
  47. return self.info.get("passwd", "123456789")
  48. class DownloadMail(Thread):
  49. def __init__(self, username, passwd, inbox, date):
  50. super(User.DownloadMail, self).__init__()
  51. self.imap = Imap(user=conf["IMAP_USERNAME"].format(username),
  52. passwd=conf["IMAP_PASSWD"].format(passwd),
  53. host=conf["IMAP_HOST"],
  54. port=conf["IMAP_PORT"],
  55. ssl=conf["IMAP_SSL"],
  56. start_ssl=conf["IMAP_START_SSL"])
  57. self.username = username
  58. self.imap.inbox = inbox
  59. self.date = date
  60. self.inbox = inbox
  61. def run(self):
  62. try:
  63. for i in redis.keys(f"mailbox:{self.username}:{self.inbox}:{self.date}:*"):
  64. num = i.split(":")[-1]
  65. byte = redis.get(i)
  66. if byte: # 避免在keys和get之前键过期
  67. self.imap.add_mail(num, byte.encode("utf-8"))
  68. self.imap.fetch_all(f"ON {self.date}")
  69. for i in self.imap.mailbox:
  70. name = f"mailbox:{self.username}:{self.inbox}:{self.date}:{i.num}"
  71. try:
  72. redis.set(name, i.byte)
  73. except UnicodeDecodeError:
  74. redis.set(name, b"")
  75. redis.expire(name, EXPIRE)
  76. except Exception:
  77. raise
  78. finally:
  79. redis.set(f"download:mutex:{self.username}", 0)
  80. def get_mail_list(self, inbox: str, date: str):
  81. imap = Imap(user=conf["IMAP_USERNAME"].format(self.username),
  82. passwd=conf["IMAP_PASSWD"].format(self.passwd),
  83. host=conf["IMAP_HOST"],
  84. port=conf["IMAP_PORT"],
  85. ssl=conf["IMAP_SSL"],
  86. start_ssl=conf["IMAP_START_SSL"])
  87. imap.inbox = inbox
  88. for i in redis.keys(f"mailbox:{self.username}:{inbox}:{date}:*"):
  89. num = i.split(":")[-1]
  90. byte = redis.get(i)
  91. if byte:
  92. imap.add_mail(num, byte.encode("utf-8"))
  93. if imap.fetch_remote_count(f"ON {date}") != 0:
  94. # 需要从远程服务器下载资源
  95. res = redis.incr(f"download:mutex:{self.username}")
  96. if res != 1:
  97. return None, False # 已经有线程
  98. th = User.DownloadMail(self.username, self.passwd, inbox, date)
  99. th.start()
  100. return imap.mailbox, True
  101. return imap.mailbox, False
  102. def get_inbox_list(self):
  103. inbox = redis.lrange(f"inbox:{self.username}", 0, -1)
  104. if len(inbox) != 0:
  105. return inbox
  106. imap = Imap(user=conf["IMAP_USERNAME"].format(self.username),
  107. passwd=conf["IMAP_PASSWD"].format(self.passwd),
  108. host=conf["IMAP_HOST"],
  109. port=conf["IMAP_PORT"],
  110. ssl=conf["IMAP_SSL"],
  111. start_ssl=conf["IMAP_START_SSL"])
  112. inbox = imap.list()
  113. redis.lpush(f"inbox:{self.username}", *inbox)
  114. redis.expire(f"inbox:{self.username}", EXPIRE)
  115. return inbox
  116. def get_mail(self, date, inbox, mail_id):
  117. name = f"mailbox:{self.username}:{inbox}:{date}:{mail_id}"
  118. byte = redis.get(name)
  119. if not byte:
  120. return None
  121. redis.expire(name, EXPIRE)
  122. return Mail(str(mail_id), byte.encode("utf-8"))
  123. def send(self, email: Email):
  124. sender = Sender(user=conf["SMTP_USERNAME"].format(self.username),
  125. passwd=conf["SMTP_PASSWD"].format(self.passwd),
  126. host=conf["SMTP_HOST"],
  127. port=conf["SMTP_PORT"],
  128. ssl=conf["SMTP_SSL"],
  129. start_ssl=conf["SMTP_START_SSL"],
  130. debug=False)
  131. sender.send(email)
  132. Logger.print_user_opt_success_log("send email")