email_parser_spec.rb 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. require 'rails_helper'
  2. RSpec.describe Channel::EmailParser, type: :model do
  3. let(:subject) { described_class.new }
  4. let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') }
  5. let(:raw_mail) { File.read(mail_file) }
  6. describe '#process' do
  7. let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, test_string) }
  8. let(:test_string) { Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number }
  9. let(:ticket) { create(:ticket) }
  10. context 'for creating new users' do
  11. context 'with one unrecognized email address' do
  12. let(:raw_mail) { <<~RAW }
  13. From: #{Faker::Internet.unique.email}
  14. To: #{User.pluck(:email).reject(&:blank?).sample}
  15. Subject: Foo bar
  16. Lorem ipsum dolor
  17. RAW
  18. it 'creates one new user' do
  19. expect { Channel::EmailParser.new.process({}, raw_mail) }
  20. .to change { User.count }.by(1)
  21. end
  22. end
  23. context 'with a large number (42+) of unrecognized email addresses' do
  24. let(:raw_mail) { <<~RAW }
  25. From: #{Faker::Internet.unique.email}
  26. To: #{Array.new(22) { Faker::Internet.unique.email }.join(', ')}
  27. Cc: #{Array.new(22) { Faker::Internet.unique.email }.join(', ')}
  28. Subject: test max sender identify
  29. Some Text
  30. RAW
  31. it 'never creates more than 41 users per email' do
  32. expect { Channel::EmailParser.new.process({}, raw_mail) }
  33. .to change { User.count }.by(41)
  34. end
  35. end
  36. end
  37. context 'for associating emails to tickets' do
  38. context 'when email subject contains ticket reference' do
  39. it 'adds message to ticket' do
  40. expect { described_class.new.process({}, raw_mail) }
  41. .to change { ticket.articles.length }
  42. end
  43. end
  44. context 'when configured to search body' do
  45. before { Setting.set('postmaster_follow_up_search_in', 'body') }
  46. context 'when body contains ticket reference' do
  47. context 'in visible text' do
  48. let(:raw_mail) { File.read(mail_file).sub(/Hallo =\nMartin,(?=<o:p>)/, test_string) }
  49. it 'adds message to ticket' do
  50. expect { described_class.new.process({}, raw_mail) }
  51. .to change { ticket.articles.length }
  52. end
  53. end
  54. context 'as part of a larger word' do
  55. let(:raw_mail) { File.read(mail_file).sub(/(?<=Hallo) =\n(?=Martin,<o:p>)/, test_string) }
  56. it 'creates a separate ticket' do
  57. expect { described_class.new.process({}, raw_mail) }
  58. .not_to change { ticket.articles.length }
  59. end
  60. end
  61. context 'in html attributes' do
  62. let(:raw_mail) { File.read(mail_file).sub(%r{<a href.*?/a>}m, %(<table bgcolor="#{test_string}"> </table>)) }
  63. it 'creates a separate ticket' do
  64. expect { described_class.new.process({}, raw_mail) }
  65. .not_to change { ticket.articles.length }
  66. end
  67. end
  68. end
  69. end
  70. end
  71. context 'for sender/recipient address formatting' do
  72. # see https://github.com/zammad/zammad/issues/2198
  73. context 'when sender address contains spaces (#2198)' do
  74. let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail071.box') }
  75. let(:sender_email) { 'powerquadrantsystem@example.com' }
  76. it 'removes them before creating a new user' do
  77. expect { described_class.new.process({}, raw_mail) }
  78. .to change { User.where(email: sender_email).count }.to(1)
  79. end
  80. it 'marks new user email as invalid' do
  81. described_class.new.process({}, raw_mail)
  82. expect(User.find_by(email: sender_email).preferences)
  83. .to include('mail_delivery_failed' => true)
  84. .and include('mail_delivery_failed_reason' => 'invalid email')
  85. .and include('mail_delivery_failed_data' => a_kind_of(ActiveSupport::TimeWithZone))
  86. end
  87. end
  88. # see https://github.com/zammad/zammad/issues/2254
  89. context 'when sender address contains > (#2254)' do
  90. let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail076.box') }
  91. let(:sender_email) { 'millionslotteryspaintransfer@example.com' }
  92. it 'removes them before creating a new user' do
  93. expect { described_class.new.process({}, raw_mail) }
  94. .to change { User.where(email: sender_email).count }.to(1)
  95. end
  96. it 'marks new user email as invalid' do
  97. described_class.new.process({}, raw_mail)
  98. expect(User.find_by(email: sender_email).preferences)
  99. .to include('mail_delivery_failed' => true)
  100. .and include('mail_delivery_failed_reason' => 'invalid email')
  101. .and include('mail_delivery_failed_data' => a_kind_of(ActiveSupport::TimeWithZone))
  102. end
  103. end
  104. end
  105. context 'for charset handling' do
  106. # see https://github.com/zammad/zammad/issues/2224
  107. context 'when header specifies Windows-1258 charset (#2224)' do
  108. let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail072.box') }
  109. it 'does not raise Encoding::ConverterNotFoundError' do
  110. expect { described_class.new.process({}, raw_mail) }
  111. .not_to raise_error
  112. end
  113. end
  114. end
  115. context 'mail with links' do
  116. def mock_mail(number_of_links)
  117. link = '<a href="https://zammad.com/">Dummy Link</a> '
  118. mail = Mail.new
  119. mail.html_part = "<html><body>#{link * number_of_links}</body></html>"
  120. mail
  121. end
  122. let(:mail_10) { mock_mail(10).to_s }
  123. let(:mail_5k) { mock_mail(5001).to_s }
  124. # regression test for issue 2390 - Add a postmaster filter to not show emails with potential issue
  125. it '(>5k links) are replaced by a warning message' do
  126. expect( described_class.new.parse(mail_5k)[:body] )
  127. .to eql( Channel::EmailParser::EXCESSIVE_LINKS_MSG )
  128. end
  129. it '(10 links) are not touched' do
  130. expect( described_class.new.parse(mail_10)[:body] )
  131. .to start_with( '<a href="https://zammad.com/"' )
  132. end
  133. end
  134. context 'Mail::Encodings.value_decode' do
  135. it 'decode us-ascii encoded strings' do
  136. expect( Mail::Encodings.value_decode('=?us-ascii?Q?Test?=') ).to eql( 'Test' )
  137. end
  138. it 'decode utf-8 encoded strings' do
  139. expect( Mail::Encodings.value_decode('=?UTF-8?Q? Personal=C3=A4nderung?=') ).to eql( ' Personaländerung' )
  140. end
  141. end
  142. end
  143. end