mailhandler 1.0.38 → 1.0.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +26 -0
  3. data/Gemfile +2 -0
  4. data/lib/mailhandler.rb +2 -10
  5. data/lib/mailhandler/errors.rb +1 -0
  6. data/lib/mailhandler/receiver.rb +14 -6
  7. data/lib/mailhandler/receiving/base.rb +28 -22
  8. data/lib/mailhandler/receiving/filelist/base.rb +17 -6
  9. data/lib/mailhandler/receiving/filelist/filter/base.rb +8 -3
  10. data/lib/mailhandler/receiving/filelist/filter/email.rb +3 -0
  11. data/lib/mailhandler/receiving/folder.rb +8 -3
  12. data/lib/mailhandler/receiving/imap.rb +53 -51
  13. data/lib/mailhandler/receiving/mail.rb +6 -13
  14. data/lib/mailhandler/receiving/notification/console.rb +2 -1
  15. data/lib/mailhandler/receiving/notification/email.rb +7 -4
  16. data/lib/mailhandler/receiving/notification/email/content.rb +1 -4
  17. data/lib/mailhandler/receiving/notification/email/states.rb +23 -20
  18. data/lib/mailhandler/receiving/observer.rb +2 -1
  19. data/lib/mailhandler/sender.rb +1 -1
  20. data/lib/mailhandler/sending/api.rb +3 -3
  21. data/lib/mailhandler/sending/api_batch.rb +4 -1
  22. data/lib/mailhandler/sending/base.rb +4 -1
  23. data/lib/mailhandler/sending/smtp.rb +0 -1
  24. data/lib/mailhandler/version.rb +1 -1
  25. data/mailhandler.gemspec +1 -2
  26. data/spec/unit/mailhandler/receiver_spec.rb +23 -15
  27. data/spec/unit/mailhandler/receiving/base_spec.rb +8 -7
  28. data/spec/unit/mailhandler/receiving/folder_spec.rb +42 -29
  29. data/spec/unit/mailhandler/receiving/imap_spec.rb +4 -5
  30. data/spec/unit/mailhandler/receiving/notification/console_spec.rb +5 -5
  31. data/spec/unit/mailhandler/receiving/notification/email/content_spec.rb +22 -18
  32. data/spec/unit/mailhandler/receiving/notification/email_spec.rb +12 -12
  33. data/spec/unit/mailhandler/sender_spec.rb +7 -3
  34. data/spec/unit/mailhandler/sending/sender_api_batch_spec.rb +9 -7
  35. data/spec/unit/mailhandler/sending/sender_api_spec.rb +4 -4
  36. data/spec/unit/mailhandler/sending/sender_smtp_spec.rb +7 -7
  37. data/spec/unit/mailhandler_spec.rb +10 -9
  38. metadata +6 -6
@@ -1,8 +1,9 @@
1
1
  module Mail
2
+ # IMAP class patch to better manage connection and search of emails
2
3
  class IMAP
3
4
  attr_accessor :imap_connection
4
5
 
5
- def find_emails(options = {}, &block)
6
+ def find_emails(options = {}, &block) # rubocop:disable all
6
7
  options = validate_options(options)
7
8
  options[:read_only] ? imap_connection.examine(options[:mailbox]) : imap_connection.select(options[:mailbox])
8
9
  uids = imap_connection.uid_search(options[:keys])
@@ -13,7 +14,6 @@ module Mail
13
14
  (options[:what].to_sym != :last && options[:order].to_sym == :desc)
14
15
 
15
16
  if block_given?
16
-
17
17
  uids.each do |uid|
18
18
  uid = options[:uid].to_i unless options[:uid].nil?
19
19
  fetchdata = imap_connection.uid_fetch(uid, ['RFC822'])[0]
@@ -26,14 +26,12 @@ module Mail
26
26
  yield new_message
27
27
  end
28
28
 
29
- imap_connection.uid_store(uid, '+FLAGS', [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
29
+ imap_connection.uid_store(uid, '+FLAGS', [Net::IMAP::DELETED]) if options[:delete_after_find] &&
30
+ new_message.is_marked_for_delete?
30
31
  break unless options[:uid].nil?
31
32
  end
32
-
33
33
  imap_connection.expunge if options[:delete_after_find]
34
-
35
34
  else
36
-
37
35
  emails = []
38
36
 
39
37
  uids.each do |uid|
@@ -46,12 +44,11 @@ module Mail
46
44
 
47
45
  imap_connection.expunge if options[:delete_after_find]
48
46
  emails.size == 1 && options[:count] == 1 ? emails.first : emails
49
-
50
47
  end
51
48
  end
52
49
 
53
50
  # Start an IMAP session
54
- def connect(_config = Mail::Configuration.instance)
51
+ def connect(_config = Mail::Configuration.instance) # rubocop:disable all
55
52
  @imap_connection = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
56
53
 
57
54
  if settings[:authentication].nil?
@@ -64,11 +61,7 @@ module Mail
64
61
  end
65
62
 
66
63
  def disconnect
67
- if defined?(imap_connection) && imap_connection && !imap_connection.disconnected?
68
-
69
- imap_connection.disconnect
70
-
71
- end
64
+ imap_connection.disconnect if defined?(imap_connection) && imap_connection && !imap_connection.disconnected?
72
65
  end
73
66
  end
74
67
  end
@@ -1,6 +1,7 @@
1
1
  module MailHandler
2
2
  module Receiving
3
3
  module Notification
4
+ # notification in form of console output
4
5
  class Console
5
6
  def notify(search)
6
7
  output_delay Time.now - search.started_at
@@ -15,7 +16,7 @@ module MailHandler
15
16
  # print to screen delay length
16
17
  def output_delay(delay)
17
18
  delay_seconds = delay.to_i
18
- output(delay_seconds) if [0, 1].include? (delay_seconds % Seconds::TO_SHOW)
19
+ output(delay_seconds) if [0, 1].include?(delay_seconds % Seconds::TO_SHOW)
19
20
  end
20
21
 
21
22
  # print to screen delay length
@@ -5,6 +5,7 @@ require_relative '../../errors'
5
5
  module MailHandler
6
6
  module Receiving
7
7
  module Notification
8
+ # notification in form of sent email
8
9
  class Email
9
10
  attr_accessor :sender,
10
11
  :from,
@@ -21,7 +22,7 @@ module MailHandler
21
22
  @from = from
22
23
  @contacts = to
23
24
  init_state
24
- set_content_handler(EmailContent.new)
25
+ change_content_handler(EmailContent.new)
25
26
  end
26
27
 
27
28
  def notify(search)
@@ -30,7 +31,7 @@ module MailHandler
30
31
  @current_state.notify(search)
31
32
  end
32
33
 
33
- def set_state(state)
34
+ def change_state(state)
34
35
  @current_state = state
35
36
  end
36
37
 
@@ -42,7 +43,7 @@ module MailHandler
42
43
 
43
44
  # Allow users to specify their own content classes.
44
45
  # Class must match by methods to the interface of MailHandler::Receiving::Notification::EmailContent
45
- def set_content_handler(content_handler)
46
+ def change_content_handler(content_handler)
46
47
  @content_handler = content_handler
47
48
  end
48
49
 
@@ -55,7 +56,9 @@ module MailHandler
55
56
  EMAIL_TYPES = %i[delayed received].freeze
56
57
 
57
58
  def verify_email_type(type)
58
- raise MailHandler::TypeError, "Incorrect type: #{type}, allowed types: #{EMAIL_TYPES}." unless EMAIL_TYPES.include? type
59
+ return if EMAIL_TYPES.include?(type)
60
+
61
+ raise MailHandler::TypeError, "Incorrect type: #{type}, allowed types: #{EMAIL_TYPES}."
59
62
  end
60
63
  end
61
64
  end
@@ -3,6 +3,7 @@ require 'mail'
3
3
  module MailHandler
4
4
  module Receiving
5
5
  module Notification
6
+ # email notification sent
6
7
  class EmailContent
7
8
  # @param [Symbol] type - notification type
8
9
  # @param [Hash] options - search options used for searching for an email
@@ -16,19 +17,15 @@ module MailHandler
16
17
  delay = (delay.to_f / 60).round(2)
17
18
 
18
19
  case type
19
-
20
20
  when :received
21
-
22
21
  mail.subject = "Received - delay was #{delay} minutes"
23
22
  mail.body = "Received - delay was #{delay} minutes - search by #{options}"
24
23
 
25
24
  when :delayed
26
-
27
25
  mail.subject = "Over #{delay} minutes delay"
28
26
  mail.body = "Over #{delay} minutes delay - search by #{options}"
29
27
 
30
28
  else
31
-
32
29
  raise StandardError, "Incorrect type: #{type}"
33
30
 
34
31
  end
@@ -4,6 +4,7 @@ require_relative '../../../errors'
4
4
  module MailHandler
5
5
  module Receiving
6
6
  module Notification
7
+ # base state
7
8
  class DelayState
8
9
  attr_accessor :context,
9
10
  :notified
@@ -23,52 +24,54 @@ module MailHandler
23
24
  protected
24
25
 
25
26
  def send_notification_email(type, search)
26
- unless notified
27
+ return if notified
27
28
 
28
- context.send_email(type, search)
29
- notification_fired
29
+ context.send_email(type, search)
30
+ notification_fired
31
+ end
30
32
 
31
- end
33
+ def change_notification_state(search, state)
34
+ context.change_state(state)
35
+ context.notify(search)
32
36
  end
33
37
  end
34
38
 
39
+ # there was no delay
35
40
  class NoDelay < DelayState
36
41
  def notify(search)
37
- if Time.now - search.started_at >= context.min_time_to_notify
42
+ return unless Time.now - search.started_at >= context.min_time_to_notify
38
43
 
39
- context.set_state(Delay.new(context))
40
- context.notify(search)
41
-
42
- end
44
+ change_notification_state(search, Delay.new(context))
43
45
  end
44
46
  end
45
47
 
48
+ # delay happened
46
49
  class Delay < DelayState
47
50
  def notify(search)
48
51
  if search.result
49
-
50
- context.set_state(Received.new(context))
51
- context.notify(search)
52
-
53
- elsif Time.now - search.started_at >= context.max_time_to_notify
54
-
55
- context.set_state(MaxDelay.new(context))
56
- context.notify(search)
57
-
52
+ change_notification_state(search, Received.new(context))
53
+ elsif max_time_to_notify?(search)
54
+ change_notification_state(search, MaxDelay.new(context))
58
55
  else
59
-
60
56
  send_notification_email(:delayed, search)
61
-
62
57
  end
63
58
  end
59
+
60
+ private
61
+
62
+ def max_time_to_notify?(search)
63
+ Time.now - search.started_at >= context.max_time_to_notify
64
+ end
64
65
  end
65
66
 
67
+ # maximum delay checked happened
66
68
  class MaxDelay < DelayState
67
69
  def notify(search)
68
70
  send_notification_email(:delayed, search)
69
71
  end
70
72
  end
71
73
 
74
+ # no more delays will be fired
72
75
  class Received < DelayState
73
76
  def notify(search)
74
77
  send_notification_email(:received, search)
@@ -1,11 +1,12 @@
1
1
  module MailHandler
2
2
  module Receiving
3
+ # observer handler
3
4
  module Observer
4
5
  def init_observer
5
6
  @observers = []
6
7
  end
7
8
 
8
- def get_observers()
9
+ def observers
9
10
  @observers
10
11
  end
11
12
 
@@ -2,8 +2,8 @@ require_relative 'sending/smtp'
2
2
  require_relative 'sending/api'
3
3
  require_relative 'sending/api_batch'
4
4
 
5
- # Class for sending email, and storing details about the sending.
6
5
  module MailHandler
6
+ # Class for sending email, and storing details about the sending.
7
7
  class Sender
8
8
  attr_accessor :dispatcher,
9
9
  :sending
@@ -4,6 +4,7 @@ require_relative 'base.rb'
4
4
 
5
5
  module MailHandler
6
6
  module Sending
7
+ # sending email by Postmark API
7
8
  class PostmarkAPISender < Sender
8
9
  attr_accessor :host,
9
10
  :api_token,
@@ -35,11 +36,10 @@ module MailHandler
35
36
  def setup_sending_client
36
37
  # clearing cache so valid host is accepted, and not the cached one
37
38
  Postmark::HttpClient.instance_variable_set('@http', nil)
38
- Postmark::ApiClient.new(api_token, http_open_timeout: http_open_timeout, http_read_timeout: http_read_timeout, host: host, secure: @use_ssl)
39
+ Postmark::ApiClient.new(api_token, http_open_timeout: http_open_timeout, http_read_timeout: http_read_timeout,
40
+ host: host, secure: @use_ssl)
39
41
  end
40
42
 
41
- protected
42
-
43
43
  DEFAULT_HOST = 'api.postmarkapp.com'.freeze
44
44
  end
45
45
  end
@@ -3,6 +3,7 @@ require_relative '../errors'
3
3
 
4
4
  module MailHandler
5
5
  module Sending
6
+ # sending batch email by Postmark API
6
7
  class PostmarkBatchAPISender < PostmarkAPISender
7
8
  def initialize(api_token = nil)
8
9
  super(api_token)
@@ -17,7 +18,9 @@ module MailHandler
17
18
  protected
18
19
 
19
20
  def verify_email(emails)
20
- raise MailHandler::TypeError, 'Invalid type error, only Array of Mail::Message object types for sending allowed' unless emails.is_a?(Array) && emails.all? { |e| e.is_a? allowed_email_type }
21
+ return if emails.is_a?(Array) && emails.all? { |e| e.is_a? allowed_email_type }
22
+
23
+ raise MailHandler::TypeError, 'Invalid type error, only Array of Mail::Message object types for sending allowed'
21
24
  end
22
25
  end
23
26
  end
@@ -2,6 +2,7 @@ require_relative '../errors'
2
2
 
3
3
  module MailHandler
4
4
  module Sending
5
+ # email sending handler class
5
6
  class Sender
6
7
  attr_reader :type
7
8
 
@@ -12,7 +13,9 @@ module MailHandler
12
13
  protected
13
14
 
14
15
  def verify_email(email)
15
- raise MailHandler::TypeError, "Invalid type error, only #{allowed_email_type} object type for sending allowed." unless email.is_a?(allowed_email_type)
16
+ return if email.is_a?(allowed_email_type)
17
+
18
+ raise MailHandler::TypeError, "Invalid type error, only #{allowed_email_type} object type for sending allowed."
16
19
  end
17
20
 
18
21
  private
@@ -1,4 +1,3 @@
1
-
2
1
  require 'net/imap'
3
2
  require_relative 'base'
4
3
 
@@ -1,3 +1,3 @@
1
1
  module MailHandler
2
- VERSION = '1.0.38'.freeze
2
+ VERSION = '1.0.39'.freeze
3
3
  end
@@ -1,4 +1,3 @@
1
-
2
1
  lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'mailhandler/version'
@@ -13,7 +12,7 @@ Gem::Specification.new do |s|
13
12
  s.email = ['ibalosh@gmail.com', 'igor@wildbit.com']
14
13
 
15
14
  s.summary = 'Postmark email receiving and sending handler.'
16
- s.description = 'Use this gem to send emails through SMTP and Postmark API. Check if email arrived by imap or folder check.'
15
+ s.description = 'Use this gem to send emails through SMTP and Postmark API and check if email arrived.'
17
16
 
18
17
  s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
19
18
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
@@ -2,21 +2,26 @@ require 'spec_helper'
2
2
 
3
3
  describe MailHandler::Receiver do
4
4
  context 'valid receiver' do
5
+ subject(:receiver) { described_class.new(checker) }
6
+
5
7
  let(:default_search_option) { { by_subject: 'test' } }
6
8
  let(:receiving_duration) { 5 }
7
9
  let(:found_email) { Mail.new { subject 'test email' } }
8
10
  let(:checker) do
9
- checker = double('Checker')
11
+ checker = instance_double('Checker')
12
+
13
+ allow(checker).to receive(:find) do
14
+ sleep receiving_duration
15
+ true
16
+ end
10
17
 
11
- allow(checker).to receive(:find) { sleep receiving_duration; true }
12
- allow(checker).to receive(:search_result) { true }
18
+ allow(checker).to receive(:search_result).and_return(true)
13
19
  allow(checker).to receive(:found_emails) { [found_email] }
14
- allow(checker).to receive(:reset_found_emails) { [] }
15
- allow(checker).to receive(:start) { nil }
16
- allow(checker).to receive(:stop) { nil }
20
+ allow(checker).to receive(:reset_found_emails).and_return([])
21
+ allow(checker).to receive(:start).and_return(nil)
22
+ allow(checker).to receive(:stop).and_return(nil)
17
23
  checker
18
24
  end
19
- subject(:receiver) { MailHandler::Receiver.new(checker) }
20
25
 
21
26
  context 'att readers' do
22
27
  it { is_expected.to respond_to(:checker) }
@@ -31,7 +36,7 @@ describe MailHandler::Receiver do
31
36
  end
32
37
 
33
38
  it 'create' do
34
- is_expected.to be_kind_of MailHandler::Receiver
39
+ expect(receiver).to be_kind_of described_class
35
40
  end
36
41
 
37
42
  it '.find_email' do
@@ -54,14 +59,17 @@ describe MailHandler::Receiver do
54
59
 
55
60
  context '.search' do
56
61
  let(:checker) do
57
- checker = double('Checker')
62
+ checker = instance_double('Checker')
58
63
 
59
- allow(checker).to receive(:find) { sleep 1; false }
60
- allow(checker).to receive(:search_result) { false }
61
- allow(checker).to receive(:found_emails) { [] }
62
- allow(checker).to receive(:reset_found_emails) { [] }
63
- allow(checker).to receive(:start) { nil }
64
- allow(checker).to receive(:stop) { nil }
64
+ allow(checker).to receive(:find) do
65
+ sleep 1
66
+ false
67
+ end
68
+ allow(checker).to receive(:search_result).and_return(false)
69
+ allow(checker).to receive(:found_emails).and_return([])
70
+ allow(checker).to receive(:reset_found_emails).and_return([])
71
+ allow(checker).to receive(:start).and_return(nil)
72
+ allow(checker).to receive(:stop).and_return(nil)
65
73
  checker
66
74
  end
67
75
 
@@ -1,25 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MailHandler::Receiving::Checker do
4
- subject { MailHandler::Receiving::Checker.new }
4
+ subject(:receiving_checker) { described_class.new }
5
5
 
6
6
  it '.create' do
7
- is_expected.to be_kind_of MailHandler::Receiving::Checker
7
+ expect(receiving_checker).to be_kind_of described_class
8
8
  end
9
9
 
10
10
  it 'init details' do
11
11
  aggregate_failures 'receiving details' do
12
- expect(subject.search_options).to eq(count: 50, archive: false)
13
- expect(subject.found_emails).to eq []
14
- expect(subject.search_result).to be false
12
+ expect(receiving_checker.search_options).to eq(count: 50, archive: false)
13
+ expect(receiving_checker.found_emails).to eq []
14
+ expect(receiving_checker.search_result).to be false
15
15
  end
16
16
  end
17
17
 
18
18
  it '.find' do
19
- expect { subject.find(by_subject: 'test') }.to raise_error(MailHandler::InterfaceError, 'Find interface not implemented.')
19
+ expect { receiving_checker.find(by_subject: 'test') }
20
+ .to raise_error(MailHandler::InterfaceError, 'Find interface not implemented.')
20
21
  end
21
22
 
22
23
  it '.search_result' do
23
- expect(subject.search_result).to be false
24
+ expect(receiving_checker.search_result).to be false
24
25
  end
25
26
  end