Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import webnotes
  5. from webnotes.utils import scrub_urls
  6. import email.utils
  7. from inlinestyler.utils import inline_css
  8. def get_email(recipients, sender='', msg='', subject='[No Subject]',
  9. text_content = None, footer=None, formatted=None):
  10. """send an html email as multipart with attachments and all"""
  11. email = EMail(sender, recipients, subject)
  12. if (not '<br>' in msg) and (not '<p>' in msg) and (not '<div' in msg):
  13. msg = msg.replace('\n', '<br>')
  14. email.set_html(msg, text_content, footer=footer, formatted=formatted)
  15. return email
  16. class EMail:
  17. """
  18. Wrapper on the email module. Email object represents emails to be sent to the client.
  19. Also provides a clean way to add binary `FileData` attachments
  20. Also sets all messages as multipart/alternative for cleaner reading in text-only clients
  21. """
  22. def __init__(self, sender='', recipients=[], subject='', alternative=0, reply_to=None):
  23. from email.mime.multipart import MIMEMultipart
  24. from email import Charset
  25. Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
  26. if isinstance(recipients, basestring):
  27. recipients = recipients.replace(';', ',').replace('\n', '')
  28. recipients = recipients.split(',')
  29. # remove null
  30. recipients = filter(None, (r.strip() for r in recipients))
  31. self.sender = sender
  32. self.reply_to = reply_to or sender
  33. self.recipients = recipients
  34. self.subject = subject
  35. self.msg_root = MIMEMultipart('mixed')
  36. self.msg_multipart = MIMEMultipart('alternative')
  37. self.msg_root.attach(self.msg_multipart)
  38. self.cc = []
  39. self.html_set = False
  40. def set_html(self, message, text_content = None, footer=None, formatted=None):
  41. """Attach message in the html portion of multipart/alternative"""
  42. if not formatted:
  43. formatted = get_formatted_html(self.subject, message, footer)
  44. # this is the first html part of a multi-part message,
  45. # convert to text well
  46. if not self.html_set:
  47. if text_content:
  48. self.set_text(text_content)
  49. else:
  50. self.set_html_as_text(message)
  51. self.set_part_html(formatted)
  52. self.html_set = True
  53. def set_text(self, message):
  54. """
  55. Attach message in the text portion of multipart/alternative
  56. """
  57. from email.mime.text import MIMEText
  58. part = MIMEText(message.encode('utf-8'), 'plain', 'utf-8')
  59. self.msg_multipart.attach(part)
  60. def set_part_html(self, message):
  61. from email.mime.text import MIMEText
  62. part = MIMEText(message.encode('utf-8'), 'html', 'utf-8')
  63. self.msg_multipart.attach(part)
  64. def set_html_as_text(self, html):
  65. """return html2text"""
  66. import HTMLParser
  67. from webnotes.utils.email_lib.html2text import html2text
  68. try:
  69. self.set_text(html2text(html))
  70. except HTMLParser.HTMLParseError:
  71. pass
  72. def set_message(self, message, mime_type='text/html', as_attachment=0, filename='attachment.html'):
  73. """Append the message with MIME content to the root node (as attachment)"""
  74. from email.mime.text import MIMEText
  75. maintype, subtype = mime_type.split('/')
  76. part = MIMEText(message, _subtype = subtype)
  77. if as_attachment:
  78. part.add_header('Content-Disposition', 'attachment', filename=filename)
  79. self.msg_root.attach(part)
  80. def attach_file(self, n):
  81. """attach a file from the `FileData` table"""
  82. from webnotes.utils.file_manager import get_file
  83. res = get_file(n)
  84. if not res:
  85. return
  86. self.add_attachment(res[0], res[1])
  87. def add_attachment(self, fname, fcontent, content_type=None):
  88. """add attachment"""
  89. from email.mime.audio import MIMEAudio
  90. from email.mime.base import MIMEBase
  91. from email.mime.image import MIMEImage
  92. from email.mime.text import MIMEText
  93. import mimetypes
  94. if not content_type:
  95. content_type, encoding = mimetypes.guess_type(fname)
  96. if content_type is None:
  97. # No guess could be made, or the file is encoded (compressed), so
  98. # use a generic bag-of-bits type.
  99. content_type = 'application/octet-stream'
  100. maintype, subtype = content_type.split('/', 1)
  101. if maintype == 'text':
  102. # Note: we should handle calculating the charset
  103. if isinstance(fcontent, unicode):
  104. fcontent = fcontent.encode("utf-8")
  105. part = MIMEText(fcontent, _subtype=subtype, _charset="utf-8")
  106. elif maintype == 'image':
  107. part = MIMEImage(fcontent, _subtype=subtype)
  108. elif maintype == 'audio':
  109. part = MIMEAudio(fcontent, _subtype=subtype)
  110. else:
  111. part = MIMEBase(maintype, subtype)
  112. part.set_payload(fcontent)
  113. # Encode the payload using Base64
  114. from email import encoders
  115. encoders.encode_base64(part)
  116. # Set the filename parameter
  117. if fname:
  118. part.add_header(b'Content-Disposition',
  119. ("attachment; filename=%s" % fname).encode('utf-8'))
  120. self.msg_root.attach(part)
  121. def validate(self):
  122. """validate the email ids"""
  123. from webnotes.utils import validate_email_add
  124. def _validate(email):
  125. """validate an email field"""
  126. if email and not validate_email_add(email):
  127. webnotes.msgprint("%s is not a valid email id" % email,
  128. raise_exception = 1)
  129. return email
  130. if not self.sender:
  131. self.sender = webnotes.conn.get_value('Email Settings', None,
  132. 'auto_email_id') or webnotes.conf.get('auto_email_id') or None
  133. if not self.sender:
  134. webnotes.msgprint("""Please specify 'Auto Email Id' \
  135. in Setup > Email Settings""")
  136. if not "expires_on" in webnotes.conf:
  137. webnotes.msgprint("""Alternatively, \
  138. you can also specify 'auto_email_id' in site_config.json""")
  139. raise webnotes.ValidationError
  140. self.sender = _validate(self.sender)
  141. self.reply_to = _validate(self.reply_to)
  142. for e in self.recipients + (self.cc or []):
  143. _validate(e.strip())
  144. def make(self):
  145. """build into msg_root"""
  146. self.msg_root['Subject'] = self.subject.encode("utf-8")
  147. self.msg_root['From'] = self.sender.encode("utf-8")
  148. self.msg_root['To'] = ', '.join([r.strip() for r in self.recipients]).encode("utf-8")
  149. self.msg_root['Date'] = email.utils.formatdate()
  150. if not self.reply_to:
  151. self.reply_to = self.sender
  152. self.msg_root['Reply-To'] = self.reply_to.encode("utf-8")
  153. if self.cc:
  154. self.msg_root['CC'] = ', '.join([r.strip() for r in self.cc]).encode("utf-8")
  155. def as_string(self):
  156. """validate, build message and convert to string"""
  157. self.validate()
  158. self.make()
  159. return self.msg_root.as_string()
  160. def get_formatted_html(subject, message, footer=None):
  161. message = scrub_urls(message)
  162. return inline_css(webnotes.get_template("templates/emails/standard.html").render({
  163. "content": message,
  164. "footer": get_footer(footer),
  165. "title": subject
  166. }))
  167. def get_footer(footer=None):
  168. """append a footer (signature)"""
  169. footer = footer or ""
  170. # control panel
  171. footer += webnotes.conn.get_value('Control Panel',None,'mail_footer') or ''
  172. # hooks
  173. for f in webnotes.get_hooks("mail_footer"):
  174. footer += webnotes.get_attr(f)
  175. footer += "<!--unsubscribe link here-->"
  176. return footer