您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

127 行
3.6 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe
  5. import smtplib
  6. import email.utils
  7. import _socket, sys
  8. from frappe import _
  9. from frappe.utils import cint, cstr, parse_addr
  10. CONNECTION_FAILED = _('Could not connect to outgoing email server')
  11. AUTH_ERROR_TITLE = _("Invalid Credentials")
  12. AUTH_ERROR = _("Incorrect email or password. Please check your login credentials.")
  13. SOCKET_ERROR_TITLE = _("Incorrect Configuration")
  14. SOCKET_ERROR = _("Invalid Outgoing Mail Server or Port")
  15. SEND_MAIL_FAILED = _("Unable to send emails at this time")
  16. EMAIL_ACCOUNT_MISSING = _('Email Account not setup. Please create a new Email Account from Setup > Email > Email Account')
  17. class InvalidEmailCredentials(frappe.ValidationError):
  18. pass
  19. def send(email, append_to=None, retry=1):
  20. """Deprecated: Send the message or add it to Outbox Email"""
  21. def _send(retry):
  22. from frappe.email.doctype.email_account.email_account import EmailAccount
  23. try:
  24. email_account = EmailAccount.find_outgoing(match_by_doctype=append_to)
  25. smtpserver = email_account.get_smtp_server()
  26. # validate is called in as_string
  27. email_body = email.as_string()
  28. smtpserver.sess.sendmail(email.sender, email.recipients + (email.cc or []), email_body)
  29. except smtplib.SMTPSenderRefused:
  30. frappe.throw(_("Invalid login or password"), title='Email Failed')
  31. raise
  32. except smtplib.SMTPRecipientsRefused:
  33. frappe.msgprint(_("Invalid recipient address"), title='Email Failed')
  34. raise
  35. except (smtplib.SMTPServerDisconnected, smtplib.SMTPAuthenticationError):
  36. if not retry:
  37. raise
  38. else:
  39. retry = retry - 1
  40. _send(retry)
  41. _send(retry)
  42. class SMTPServer:
  43. def __init__(self, server, login=None, password=None, port=None, use_tls=None, use_ssl=None):
  44. self.login = login
  45. self.password = password
  46. self._server = server
  47. self._port = port
  48. self.use_tls = use_tls
  49. self.use_ssl = use_ssl
  50. self._session = None
  51. if not self.server:
  52. frappe.msgprint(EMAIL_ACCOUNT_MISSING, raise_exception=frappe.OutgoingEmailError)
  53. @property
  54. def port(self):
  55. port = self._port or (self.use_ssl and 465) or (self.use_tls and 587)
  56. return cint(port)
  57. @property
  58. def server(self):
  59. return cstr(self._server or "")
  60. def secure_session(self, conn):
  61. """Secure the connection incase of TLS.
  62. """
  63. if self.use_tls:
  64. conn.ehlo()
  65. conn.starttls()
  66. conn.ehlo()
  67. @property
  68. def session(self):
  69. if self.is_session_active():
  70. return self._session
  71. SMTP = smtplib.SMTP_SSL if self.use_ssl else smtplib.SMTP
  72. try:
  73. self._session = SMTP(self.server, self.port)
  74. if not self._session:
  75. frappe.msgprint(CONNECTION_FAILED, raise_exception=frappe.OutgoingEmailError)
  76. self.secure_session(self._session)
  77. if self.login and self.password:
  78. res = self._session.login(str(self.login or ""), str(self.password or ""))
  79. # check if logged correctly
  80. if res[0]!=235:
  81. frappe.msgprint(res[1], raise_exception=frappe.OutgoingEmailError)
  82. return self._session
  83. except smtplib.SMTPAuthenticationError as e:
  84. self.throw_invalid_credentials_exception()
  85. except _socket.error as e:
  86. # Invalid mail server -- due to refusing connection
  87. frappe.throw(SOCKET_ERROR, title=SOCKET_ERROR_TITLE)
  88. except smtplib.SMTPException:
  89. frappe.msgprint(SEND_MAIL_FAILED)
  90. raise
  91. def is_session_active(self):
  92. if self._session:
  93. try:
  94. return self._session.noop()[0] == 250
  95. except Exception:
  96. return False
  97. def quit(self):
  98. if self.is_session_active():
  99. self._session.quit()
  100. @classmethod
  101. def throw_invalid_credentials_exception(cls):
  102. frappe.throw(AUTH_ERROR, title=AUTH_ERROR_TITLE, exc=InvalidEmailCredentials)