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ů.
 
 
 
 
 
 

153 řádky
3.4 KiB

  1. """
  2. This module contains classes for managing incoming emails
  3. """
  4. class IncomingMail:
  5. """
  6. Single incoming email object. Extracts, text / html and attachments from the email
  7. """
  8. def __init__(self, content):
  9. """
  10. Parse the incoming mail content
  11. """
  12. import email
  13. self.mail = email.message_from_string(content)
  14. self.text_content = ''
  15. self.html_content = ''
  16. self.attachments = []
  17. self.parse()
  18. def get_text_content(self):
  19. """
  20. Returns the text parts of the email. If None, then HTML parts
  21. """
  22. return self.text_content or self.html_content
  23. def get_charset(self, part):
  24. """
  25. Guesses character set
  26. """
  27. charset = part.get_content_charset()
  28. if not charset:
  29. import chardet
  30. charset = chardet.detect(str(part))['encoding']
  31. return charset
  32. def get_payload(self, part, charset):
  33. """
  34. get utf-8 encoded part content
  35. """
  36. try:
  37. return unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace')
  38. except LookupError, e:
  39. return part.get_payload()
  40. def get_attachment(self, part, charset):
  41. """
  42. Extracts an attachment
  43. """
  44. self.attachments.append({
  45. 'content-type': part.get_content_type(),
  46. 'filename': part.get_filename(),
  47. 'content': self.get_payload(part, charset)
  48. })
  49. def parse(self):
  50. """
  51. Extracts text, html and attachments from the mail
  52. """
  53. for part in self.mail.walk():
  54. self.process_part(part)
  55. def get_thread_id(self):
  56. """
  57. Extracts thread id of the message between first []
  58. from the subject
  59. """
  60. subject = self.mail.get('Subject', '')
  61. if '[' in subject and ']' in subject:
  62. return subject.split('[')[1].split(']')[0]
  63. def process_part(self, part):
  64. """
  65. Process a single part of an email
  66. """
  67. charset = self.get_charset(part)
  68. content_type = part.get_content_type()
  69. if content_type == 'text/plain':
  70. self.text_content += self.get_payload(part, charset)
  71. if content_type == 'text/html':
  72. self.html_content += self.get_payload(part, charset)
  73. if part.get_filename():
  74. self.get_attachment(part, charset)
  75. class POP3Mailbox:
  76. """
  77. A simple pop3 mailbox, abstracts connection and mail extraction
  78. To use, subclass it and override method process_message(from, subject, text, thread_id)
  79. """
  80. def __init__(self, settings_doc):
  81. """
  82. settings_doc must contain
  83. is_ssl, host, username, password
  84. (by name or object)
  85. """
  86. if type(settings_doc)==str:
  87. from webnotes.model.doc import Document
  88. self.settings = Document(settings_doc, settings_doc)
  89. else:
  90. self.settings = settings_doc
  91. def connect(self):
  92. """
  93. Connects to the mailbox
  94. """
  95. import poplib
  96. if self.settings.use_ssl:
  97. self.pop = poplib.POP3_SSL(self.settings.host)
  98. else:
  99. self.pop = poplib.POP3(self.settings.host)
  100. self.pop.user(self.settings.username)
  101. self.pop.pass_(self.settings.password)
  102. def get_messages(self):
  103. """
  104. Loads messages from the mailbox and calls
  105. process_message for each message
  106. """
  107. if not self.check_mails():
  108. return # nothing to do
  109. self.connect()
  110. num = len(self.pop.list()[1])
  111. for m in range(num):
  112. msg = self.pop.retr(m+1)
  113. try:
  114. self.process_message(IncomingMail('\n'.join(msg[1])))
  115. except:
  116. pass
  117. self.pop.dele(m+1)
  118. self.pop.quit()
  119. def check_mails(self):
  120. """
  121. To be overridden
  122. If mailbox is to be scanned, returns true
  123. """
  124. return True
  125. def process_message(self, mail):
  126. """
  127. To be overriden
  128. """
  129. pass