mailbox.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. from smtplib import SMTPRecipientsRefused
  2. from flask import g
  3. from flask import jsonify
  4. from flask import request
  5. from flask_cors import cross_origin
  6. from app.api.base import api_bp, require_api_auth
  7. from app.dashboard.views.mailbox import send_verification_email
  8. from app.dashboard.views.mailbox_detail import verify_mailbox_change
  9. from app.email_utils import (
  10. mailbox_already_used,
  11. email_domain_can_be_used_as_mailbox,
  12. )
  13. from app.extensions import db
  14. from app.models import Mailbox
  15. @api_bp.route("/mailboxes", methods=["POST"])
  16. @cross_origin()
  17. @require_api_auth
  18. def create_mailbox():
  19. """
  20. Create a new mailbox. User needs to verify the mailbox via an activation email.
  21. Input:
  22. email: in body
  23. Output:
  24. the new mailbox
  25. - id
  26. - email
  27. - verified
  28. """
  29. user = g.user
  30. mailbox_email = request.get_json().get("email").lower().strip()
  31. if mailbox_already_used(mailbox_email, user):
  32. return jsonify(error=f"{mailbox_email} already used"), 400
  33. elif not email_domain_can_be_used_as_mailbox(mailbox_email):
  34. return (
  35. jsonify(
  36. error=f"{mailbox_email} cannot be used. Please note a mailbox cannot "
  37. f"be a disposable email address"
  38. ),
  39. 400,
  40. )
  41. else:
  42. new_mailbox = Mailbox.create(email=mailbox_email, user_id=user.id)
  43. db.session.commit()
  44. send_verification_email(user, new_mailbox)
  45. return (
  46. jsonify(
  47. id=new_mailbox.id,
  48. email=new_mailbox.email,
  49. verified=new_mailbox.verified,
  50. default=user.default_mailbox_id == new_mailbox.id,
  51. ),
  52. 201,
  53. )
  54. @api_bp.route("/mailboxes/<mailbox_id>", methods=["DELETE"])
  55. @cross_origin()
  56. @require_api_auth
  57. def delete_mailbox(mailbox_id):
  58. """
  59. Delete mailbox
  60. Input:
  61. mailbox_id: in url
  62. Output:
  63. 200 if deleted successfully
  64. """
  65. user = g.user
  66. mailbox = Mailbox.get(mailbox_id)
  67. if not mailbox or mailbox.user_id != user.id:
  68. return jsonify(error="Forbidden"), 403
  69. if mailbox.id == user.default_mailbox_id:
  70. return jsonify(error="You cannot delete the default mailbox"), 400
  71. Mailbox.delete(mailbox_id)
  72. db.session.commit()
  73. return jsonify(deleted=True), 200
  74. @api_bp.route("/mailboxes/<mailbox_id>", methods=["PUT"])
  75. @cross_origin()
  76. @require_api_auth
  77. def update_mailbox(mailbox_id):
  78. """
  79. Update mailbox
  80. Input:
  81. mailbox_id: in url
  82. (optional) default: in body. Set a mailbox as the default mailbox.
  83. (optional) email: in body. Change a mailbox email.
  84. (optional) cancel_email_change: in body. Cancel mailbox email change.
  85. Output:
  86. 200 if updated successfully
  87. """
  88. user = g.user
  89. mailbox = Mailbox.get(mailbox_id)
  90. if not mailbox or mailbox.user_id != user.id:
  91. return jsonify(error="Forbidden"), 403
  92. data = request.get_json() or {}
  93. changed = False
  94. if "default" in data:
  95. is_default = data.get("default")
  96. if is_default:
  97. user.default_mailbox_id = mailbox.id
  98. changed = True
  99. if "email" in data:
  100. new_email = data.get("email").lower().strip()
  101. if mailbox_already_used(new_email, user):
  102. return jsonify(error=f"{new_email} already used"), 400
  103. elif not email_domain_can_be_used_as_mailbox(new_email):
  104. return (
  105. jsonify(
  106. error=f"{new_email} cannot be used. Please note a mailbox cannot "
  107. f"be a disposable email address"
  108. ),
  109. 400,
  110. )
  111. try:
  112. verify_mailbox_change(user, mailbox, new_email)
  113. except SMTPRecipientsRefused:
  114. return jsonify(error=f"Incorrect mailbox, please recheck {new_email}"), 400
  115. else:
  116. mailbox.new_email = new_email
  117. changed = True
  118. if "cancel_email_change" in data:
  119. cancel_email_change = data.get("cancel_email_change")
  120. if cancel_email_change:
  121. mailbox.new_email = None
  122. changed = True
  123. if changed:
  124. db.session.commit()
  125. return jsonify(updated=True), 200
  126. @api_bp.route("/mailboxes", methods=["GET"])
  127. @cross_origin()
  128. @require_api_auth
  129. def get_mailboxes():
  130. """
  131. Get mailboxes
  132. Output:
  133. - mailboxes: list of alias:
  134. - id
  135. - email
  136. - default: boolean - whether the mailbox is the default one
  137. - creation_timestamp
  138. """
  139. user = g.user
  140. return (
  141. jsonify(
  142. mailboxes=[
  143. {
  144. "id": mb.id,
  145. "email": mb.email,
  146. "default": user.default_mailbox_id == mb.id,
  147. "creation_timestamp": mb.created_at.timestamp,
  148. }
  149. for mb in user.mailboxes()
  150. ]
  151. ),
  152. 200,
  153. )