Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

211 řádky
6.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.utils import cint
  9. from frappe import _
  10. def send(email, append_to=None, retry=1):
  11. """send the message or add it to Outbox Email"""
  12. if frappe.flags.in_test:
  13. frappe.flags.sent_mail = email.as_string()
  14. return
  15. if frappe.are_emails_muted():
  16. frappe.msgprint(_("Emails are muted"))
  17. return
  18. def _send(retry):
  19. try:
  20. smtpserver = SMTPServer(append_to=append_to)
  21. # validate is called in as_string
  22. email_body = email.as_string()
  23. smtpserver.sess.sendmail(email.sender, email.recipients + (email.cc or []), email_body)
  24. except smtplib.SMTPSenderRefused:
  25. frappe.throw(_("Invalid login or password"), title='Email Failed')
  26. raise
  27. except smtplib.SMTPRecipientsRefused:
  28. frappe.msgprint(_("Invalid recipient address"), title='Email Failed')
  29. raise
  30. except smtplib.SMTPServerDisconnected:
  31. if not retry:
  32. raise
  33. else:
  34. retry = retry - 1
  35. _send(retry)
  36. _send(retry)
  37. def get_outgoing_email_account(raise_exception_not_set=True, append_to=None):
  38. """Returns outgoing email account based on `append_to` or the default
  39. outgoing account. If default outgoing account is not found, it will
  40. try getting settings from `site_config.json`."""
  41. if not getattr(frappe.local, "outgoing_email_account", None):
  42. frappe.local.outgoing_email_account = {}
  43. if not frappe.local.outgoing_email_account.get(append_to or "default"):
  44. email_account = None
  45. if append_to:
  46. # append_to is only valid when enable_incoming is checked
  47. email_account = _get_email_account({"enable_outgoing": 1, "enable_incoming": 1, "append_to": append_to})
  48. if not email_account:
  49. email_account = get_default_outgoing_email_account(raise_exception_not_set=raise_exception_not_set)
  50. if not email_account and raise_exception_not_set:
  51. frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"),
  52. frappe.OutgoingEmailError)
  53. if email_account:
  54. email_account.password = email_account.get_password()
  55. email_account.default_sender = email.utils.formataddr((email_account.name, email_account.get("email_id")))
  56. frappe.local.outgoing_email_account[append_to or "default"] = email_account
  57. return frappe.local.outgoing_email_account[append_to or "default"]
  58. def get_default_outgoing_email_account(raise_exception_not_set=True):
  59. '''conf should be like:
  60. {
  61. "mail_server": "smtp.example.com",
  62. "mail_port": 587,
  63. "use_ssl": 1,
  64. "mail_login": "emails@example.com",
  65. "mail_password": "Super.Secret.Password",
  66. "auto_email_id": "emails@example.com",
  67. "email_sender_name": "Example Notifications",
  68. "always_use_account_email_id_as_sender": 0
  69. }
  70. '''
  71. email_account = _get_email_account({"enable_outgoing": 1, "default_outgoing": 1})
  72. if email_account:
  73. email_account.password = email_account.get_password()
  74. if not email_account and frappe.conf.get("mail_server"):
  75. # from site_config.json
  76. email_account = frappe.new_doc("Email Account")
  77. email_account.update({
  78. "smtp_server": frappe.conf.get("mail_server"),
  79. "smtp_port": frappe.conf.get("mail_port"),
  80. "use_tls": cint(frappe.conf.get("use_ssl") or 0),
  81. "login_id": frappe.conf.get("mail_login"),
  82. "email_id": frappe.conf.get("auto_email_id") or frappe.conf.get("mail_login") or 'notifications@example.com',
  83. "password": frappe.conf.get("mail_password"),
  84. "always_use_account_email_id_as_sender": frappe.conf.get("always_use_account_email_id_as_sender", 0)
  85. })
  86. email_account.from_site_config = True
  87. email_account.name = frappe.conf.get("email_sender_name") or "Frappe"
  88. if not email_account and not raise_exception_not_set:
  89. return None
  90. if frappe.are_emails_muted():
  91. # create a stub
  92. email_account = frappe.new_doc("Email Account")
  93. email_account.update({
  94. "email_id": "notifications@example.com"
  95. })
  96. return email_account
  97. def _get_email_account(filters):
  98. name = frappe.db.get_value("Email Account", filters)
  99. return frappe.get_doc("Email Account", name) if name else None
  100. class SMTPServer:
  101. def __init__(self, login=None, password=None, server=None, port=None, use_ssl=None, append_to=None):
  102. # get defaults from mail settings
  103. self._sess = None
  104. self.email_account = None
  105. self.server = None
  106. if server:
  107. self.server = server
  108. self.port = port
  109. self.use_ssl = cint(use_ssl)
  110. self.login = login
  111. self.password = password
  112. else:
  113. self.setup_email_account(append_to)
  114. def setup_email_account(self, append_to=None):
  115. self.email_account = get_outgoing_email_account(raise_exception_not_set=False, append_to=append_to)
  116. if self.email_account:
  117. self.server = self.email_account.smtp_server
  118. self.login = getattr(self.email_account, "login_id", None) or self.email_account.email_id
  119. self.password = self.email_account.password
  120. self.port = self.email_account.smtp_port
  121. self.use_ssl = self.email_account.use_tls
  122. self.sender = self.email_account.email_id
  123. self.always_use_account_email_id_as_sender = cint(self.email_account.get("always_use_account_email_id_as_sender"))
  124. @property
  125. def sess(self):
  126. """get session"""
  127. if self._sess:
  128. return self._sess
  129. # check if email server specified
  130. if not getattr(self, 'server'):
  131. err_msg = _('Email Account not setup. Please create a new Email Account from Setup > Email > Email Account')
  132. frappe.msgprint(err_msg)
  133. raise frappe.OutgoingEmailError, err_msg
  134. try:
  135. if self.use_ssl and not self.port:
  136. self.port = 587
  137. self._sess = smtplib.SMTP((self.server or "").encode('utf-8'),
  138. cint(self.port) or None)
  139. if not self._sess:
  140. err_msg = _('Could not connect to outgoing email server')
  141. frappe.msgprint(err_msg)
  142. raise frappe.OutgoingEmailError, err_msg
  143. if self.use_ssl:
  144. self._sess.ehlo()
  145. self._sess.starttls()
  146. self._sess.ehlo()
  147. if self.login and self.password:
  148. ret = self._sess.login((self.login or "").encode('utf-8'),
  149. (self.password or "").encode('utf-8'))
  150. # check if logged correctly
  151. if ret[0]!=235:
  152. frappe.msgprint(ret[1])
  153. raise frappe.OutgoingEmailError, ret[1]
  154. return self._sess
  155. except _socket.error, e:
  156. # Invalid mail server -- due to refusing connection
  157. frappe.msgprint(_('Invalid Outgoing Mail Server or Port'))
  158. type, value, traceback = sys.exc_info()
  159. raise frappe.ValidationError, e, traceback
  160. except smtplib.SMTPAuthenticationError, e:
  161. frappe.msgprint(_("Invalid login or password"))
  162. type, value, traceback = sys.exc_info()
  163. raise frappe.ValidationError, e, traceback
  164. except smtplib.SMTPException:
  165. frappe.msgprint(_('Unable to send emails at this time'))
  166. raise