imap.rb 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. require 'net/imap'
  3. class Channel::Driver::Imap < Channel::EmailParser
  4. def fetchable?(_channel)
  5. true
  6. end
  7. =begin
  8. fetch emails from IMAP account
  9. instance = Channel::Driver::Imap.new
  10. result = instance.fetch(params[:inbound][:options], channel, 'verify', subject_looking_for)
  11. returns
  12. {
  13. result: 'ok',
  14. fetched: 123,
  15. notice: 'e. g. message about to big emails in mailbox',
  16. }
  17. check if connect to IMAP account is possible, return count of mails in mailbox
  18. instance = Channel::Driver::Imap.new
  19. result = instance.fetch(params[:inbound][:options], channel, 'check')
  20. returns
  21. {
  22. result: 'ok',
  23. content_messages: 123,
  24. }
  25. verify IMAP account, check if search email is in there
  26. instance = Channel::Driver::Imap.new
  27. result = instance.fetch(params[:inbound][:options], channel, 'verify', subject_looking_for)
  28. returns
  29. {
  30. result: 'ok', # 'verify not ok'
  31. }
  32. example
  33. params = {
  34. host: 'outlook.office365.com',
  35. user: 'xxx@znuny.onmicrosoft.com',
  36. password: 'xxx',
  37. }
  38. channel = Channel.last
  39. instance = Channel::Driver::Imap.new
  40. result = instance.fetch(params, channel, 'verify')
  41. =end
  42. def fetch (options, channel, check_type = '', verify_string = '')
  43. ssl = true
  44. port = 993
  45. if options.key?(:ssl) && options[:ssl] == false
  46. ssl = false
  47. port = 143
  48. end
  49. if options.key?(:port) && !options[:port].empty?
  50. port = options[:port]
  51. # disable ssl for non ssl ports
  52. if port == 143 && !options.key?(:ssl)
  53. ssl = false
  54. end
  55. end
  56. Rails.logger.info "fetching imap (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})"
  57. # on check, reduce open_timeout to have faster probing
  58. timeout = 24
  59. if check_type == 'check'
  60. timeout = 6
  61. end
  62. Timeout.timeout(timeout) do
  63. @imap = Net::IMAP.new(options[:host], port, ssl, nil, false)
  64. end
  65. @imap.login(options[:user], options[:password])
  66. # select folder
  67. if !options[:folder] || options[:folder].empty?
  68. @imap.select('INBOX')
  69. else
  70. @imap.select(options[:folder])
  71. end
  72. # sort messages by date on server (if not supported), if not fetch messages via search (first in, first out)
  73. begin
  74. message_ids = @imap.sort(['DATE'], ['ALL'], 'US-ASCII')
  75. rescue
  76. message_ids = @imap.search(['ALL'])
  77. end
  78. # check mode only
  79. if check_type == 'check'
  80. Rails.logger.info 'check only mode, fetch no emails'
  81. content_max_check = 2
  82. content_messages = 0
  83. # check messages
  84. message_ids.each do |message_id|
  85. message_meta = @imap.fetch(message_id, ['RFC822.HEADER'])[0].attr
  86. # check how many content messages we have, for notice used
  87. header = message_meta['RFC822.HEADER']
  88. if header && header !~ /x-zammad-ignore/i
  89. content_messages += 1
  90. break if content_max_check < content_messages
  91. end
  92. end
  93. if content_messages >= content_max_check
  94. content_messages = message_ids.count
  95. end
  96. disconnect
  97. return {
  98. result: 'ok',
  99. content_messages: content_messages,
  100. }
  101. end
  102. # reverse message order to increase performance
  103. if check_type == 'verify'
  104. Rails.logger.info "verify mode, fetch no emails #{verify_string}"
  105. message_ids.reverse!
  106. # check for verify message
  107. message_ids.each do |message_id|
  108. message_meta = @imap.fetch(message_id, ['ENVELOPE'])[0].attr
  109. # check if verify message exists
  110. subject = message_meta['ENVELOPE'].subject
  111. next if !subject
  112. next if subject !~ /#{verify_string}/
  113. Rails.logger.info " - verify email #{verify_string} found"
  114. @imap.store(message_id, '+FLAGS', [:Deleted])
  115. @imap.expunge()
  116. disconnect
  117. return {
  118. result: 'ok',
  119. }
  120. end
  121. disconnect
  122. return {
  123. result: 'verify not ok',
  124. }
  125. end
  126. # fetch regular messages
  127. count_all = message_ids.count
  128. count = 0
  129. count_fetched = 0
  130. notice = ''
  131. message_ids.each do |message_id|
  132. count += 1
  133. Rails.logger.info " - message #{count}/#{count_all}"
  134. #Rails.logger.info msg.to_s
  135. message_meta = @imap.fetch(message_id, ['RFC822.SIZE', 'FLAGS', 'INTERNALDATE'])[0]
  136. # ignore to big messages
  137. max_message_size = Setting.get('postmaster_max_size').to_f
  138. real_message_size = message_meta.attr['RFC822.SIZE'].to_f / 1024 / 1024
  139. if real_message_size > max_message_size
  140. info = " - ignore message #{count}/#{count_all} - because message is too big (is:#{real_message_size} MB/max:#{max_message_size} MB)"
  141. Rails.logger.info info
  142. notice += "#{info}\n"
  143. next
  144. end
  145. # ignore deleted messages
  146. if message_meta.attr['FLAGS'].include?(:Deleted)
  147. Rails.logger.info " - ignore message #{count}/#{count_all} - because message has already delete flag"
  148. next
  149. end
  150. # delete email from server after article was created
  151. msg = @imap.fetch(message_id, 'RFC822')[0].attr['RFC822']
  152. next if !msg
  153. process(channel, msg, false)
  154. @imap.store(message_id, '+FLAGS', [:Deleted])
  155. count_fetched += 1
  156. end
  157. @imap.expunge()
  158. disconnect
  159. if count.zero?
  160. Rails.logger.info ' - no message'
  161. end
  162. Rails.logger.info 'done'
  163. {
  164. result: 'ok',
  165. fetched: count_fetched,
  166. notice: notice,
  167. }
  168. end
  169. def disconnect
  170. return if !@imap
  171. @imap.disconnect()
  172. end
  173. end