user.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. Logger.print_user_opt_fail_log(f"thread load email")
  78. raise
  79. else:
  80. Logger.print_user_opt_success_log(f"thread load email")
  81. finally:
  82. redis.set(f"download:mutex:{self.username}", 0)
  83. def get_mail_list(self, inbox: str, date: str):
  84. imap = Imap(user=conf["IMAP_USERNAME"].format(self.username),
  85. passwd=conf["IMAP_PASSWD"].format(self.passwd),
  86. host=conf["IMAP_HOST"],
  87. port=conf["IMAP_PORT"],
  88. ssl=conf["IMAP_SSL"],
  89. start_ssl=conf["IMAP_START_SSL"])
  90. imap.inbox = inbox
  91. for i in redis.keys(f"mailbox:{self.username}:{inbox}:{date}:*"):
  92. num = i.split(":")[-1]
  93. byte = redis.get(i)
  94. if byte:
  95. imap.add_mail(num, byte.encode("utf-8"))
  96. if imap.fetch_remote_count(f"ON {date}") != 0:
  97. # 需要从远程服务器下载资源
  98. res = redis.incr(f"download:mutex:{self.username}")
  99. if res != 1:
  100. return None, False # 已经有线程
  101. th = User.DownloadMail(self.username, self.passwd, inbox, date)
  102. th.start()
  103. return imap.mailbox, True
  104. return imap.mailbox, False
  105. def get_inbox_list(self):
  106. inbox = redis.lrange(f"inbox:{self.username}", 0, -1)
  107. if len(inbox) != 0:
  108. return inbox
  109. imap = Imap(user=conf["IMAP_USERNAME"].format(self.username),
  110. passwd=conf["IMAP_PASSWD"].format(self.passwd),
  111. host=conf["IMAP_HOST"],
  112. port=conf["IMAP_PORT"],
  113. ssl=conf["IMAP_SSL"],
  114. start_ssl=conf["IMAP_START_SSL"])
  115. inbox = imap.list()
  116. redis.lpush(f"inbox:{self.username}", *inbox)
  117. redis.expire(f"inbox:{self.username}", EXPIRE)
  118. return inbox
  119. def get_mail(self, date, inbox, mail_id):
  120. name = f"mailbox:{self.username}:{inbox}:{date}:{mail_id}"
  121. byte = redis.get(name)
  122. if not byte:
  123. return None
  124. redis.expire(name, EXPIRE)
  125. return Mail(str(mail_id), byte.encode("utf-8"))
  126. def send(self, email: Email):
  127. sender = Sender(user=conf["SMTP_USERNAME"].format(self.username),
  128. passwd=conf["SMTP_PASSWD"].format(self.passwd),
  129. host=conf["SMTP_HOST"],
  130. port=conf["SMTP_PORT"],
  131. ssl=conf["SMTP_SSL"],
  132. start_ssl=conf["SMTP_START_SSL"],
  133. debug=False)
  134. sender.send(email)
  135. Logger.print_user_opt_success_log("send email")