mailbox.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import imaplib
  2. from functools import wraps
  3. from flask import Blueprint, render_template, request, flash, abort, make_response, redirect, url_for
  4. from flask_login import login_required, current_user
  5. from flask_wtf import FlaskForm
  6. from wtforms import DateField, SelectField, SubmitField
  7. from wtforms.validators import DataRequired
  8. from time import strftime, strptime, mktime, localtime
  9. from typing import List
  10. from mailbox.email import Mail, HTML, PLAIN
  11. from .page import get_page, get_max_page
  12. from .logger import Logger
  13. mailbox = Blueprint("mailbox", __name__)
  14. class ToMailboxForm(FlaskForm):
  15. date = DateField("发信时间", description="信件发送时间", validators=[DataRequired("必须选择时间")])
  16. select = SelectField("文件夹", description="INBOX或其他文件夹", validators=[DataRequired("必须选择文件夹")])
  17. submit = SubmitField("查询")
  18. def __init__(self, select: list):
  19. super(ToMailboxForm, self).__init__()
  20. try:
  21. del select[select.index("INBOX")]
  22. select = ["INBOX"] + select
  23. except ValueError:
  24. pass
  25. self.select.choices = select
  26. self.select.coerce = str
  27. self.select.default = "INBOX"
  28. def except_imap_error(func):
  29. @wraps(func)
  30. def new_func(*args, **kwargs):
  31. try:
  32. res = func(*args, **kwargs)
  33. except imaplib.IMAP4.error:
  34. flash("IMAP连接异常, 请重新尝试")
  35. return redirect(url_for("mailbox.mail_list_page"))
  36. else:
  37. return res
  38. return new_func
  39. def __load_mailbox_page(mail_list, page, to_mail=None, date=None, select=None, next_date=None, last_date=None):
  40. if not to_mail:
  41. to_mail = ToMailboxForm(current_user.get_inbox_list())
  42. max_page = get_max_page(len(mail_list), 10)
  43. page_list = get_page("mailbox.mail_list_page", page, max_page, date=date, select=select)
  44. page_mail_list: List[Mail] = mail_list[(page - 1) * 10: page * 10]
  45. Logger.print_load_page_log(f"mail-list date:{date} select:{select}")
  46. return render_template("mailbox/mailbox.html",
  47. to_mail=to_mail,
  48. date=date,
  49. select=select,
  50. page_list=page_list,
  51. page=page,
  52. mail_list=page_mail_list,
  53. max_page=max_page,
  54. empty=(len(page_mail_list) == 0),
  55. next_date=next_date,
  56. last_date=last_date)
  57. @mailbox.route("/")
  58. @login_required
  59. @except_imap_error
  60. def mail_list_page():
  61. date = request.args.get("date", None, type=str)
  62. select = request.args.get("select", "INBOX", type=str)
  63. page = request.args.get("page", 1, type=int)
  64. if date:
  65. date_obj = strptime(date, "%Y-%m-%d")
  66. mail_list, download = current_user.get_mail_list(select, strftime('%d-%b-%Y', date_obj))
  67. if mail_list is None and not download:
  68. flash("旧任务未完成,正在下载邮件,请稍后")
  69. mail_list = []
  70. elif download:
  71. flash("启动新任务下载邮件,请稍后")
  72. next_date = strftime("%Y-%m-%d", localtime(mktime(date_obj) + 24 * 60 * 60))
  73. last_date = strftime("%Y-%m-%d", localtime(mktime(date_obj) - 24 * 60 * 60))
  74. else:
  75. mail_list = []
  76. next_date = None
  77. last_date = None
  78. return __load_mailbox_page(mail_list,
  79. page,
  80. date=date,
  81. select=select,
  82. next_date=next_date,
  83. last_date=last_date)
  84. def __get_mail() -> (Mail, str, str, int):
  85. mail_id = request.args.get("mail", None, type=int)
  86. date = request.args.get("date", None, type=str)
  87. select = request.args.get("select", None, type=str)
  88. if not mail_id or not date or not select:
  89. abort(404)
  90. date_obj = strftime('%d-%b-%Y', strptime(date, "%Y-%m-%d"))
  91. mail: Mail = current_user.get_mail(date_obj, select, mail_id)
  92. if not mail:
  93. abort(404)
  94. return mail, date, select, mail_id
  95. @mailbox.route("/html")
  96. @login_required
  97. @except_imap_error
  98. def html_page():
  99. html_id = request.args.get("id", 1, type=int)
  100. mail, *_ = __get_mail()
  101. count = 0
  102. for i in mail.body_list:
  103. count += 1
  104. if type(i) is HTML:
  105. if count == html_id:
  106. return i.body
  107. return abort(404)
  108. @mailbox.route("/file")
  109. @login_required
  110. @except_imap_error
  111. def file_page():
  112. filename = request.args.get("filename", None, type=str)
  113. if not filename:
  114. abort(404)
  115. mail, *_ = __get_mail()
  116. byte, content_type, content_disposition = mail.get_file(filename)
  117. if not byte:
  118. abort(404)
  119. response = make_response(byte)
  120. response.headers['Content-Type'] = content_type
  121. response.headers['Content-Disposition'] = content_disposition
  122. return response
  123. @mailbox.route("/mail")
  124. @login_required
  125. @except_imap_error
  126. def mail_page():
  127. mail, date, select, mail_id = __get_mail()
  128. count = 0
  129. html_id = []
  130. plain = []
  131. for i in mail.body_list:
  132. count += 1
  133. if type(i) is HTML:
  134. html_id.append(count)
  135. elif type(i) is PLAIN:
  136. plain.append(i)
  137. file_list = mail.file_list
  138. Logger.print_load_page_log(f"mail-{mail_id}")
  139. return render_template("mailbox/mail.html",
  140. date=date,
  141. select=select,
  142. mail_id=mail_id,
  143. mail=mail,
  144. html_id=html_id,
  145. plain=plain,
  146. file_list=file_list)