mailhandler 1.0.36 → 1.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Rakefile +2 -2
  4. data/lib/mailhandler.rb +13 -37
  5. data/lib/mailhandler/errors.rb +1 -5
  6. data/lib/mailhandler/receiver.rb +4 -22
  7. data/lib/mailhandler/receiving/base.rb +16 -45
  8. data/lib/mailhandler/receiving/filelist/base.rb +25 -49
  9. data/lib/mailhandler/receiving/filelist/filter/base.rb +10 -52
  10. data/lib/mailhandler/receiving/filelist/filter/email.rb +4 -44
  11. data/lib/mailhandler/receiving/folder.rb +16 -54
  12. data/lib/mailhandler/receiving/imap.rb +34 -78
  13. data/lib/mailhandler/receiving/mail.rb +5 -19
  14. data/lib/mailhandler/receiving/notification/console.rb +2 -18
  15. data/lib/mailhandler/receiving/notification/email.rb +5 -28
  16. data/lib/mailhandler/receiving/notification/email/content.rb +9 -20
  17. data/lib/mailhandler/receiving/notification/email/states.rb +1 -36
  18. data/lib/mailhandler/receiving/observer.rb +5 -16
  19. data/lib/mailhandler/sender.rb +2 -14
  20. data/lib/mailhandler/sending/api.rb +1 -7
  21. data/lib/mailhandler/sending/api_batch.rb +1 -13
  22. data/lib/mailhandler/sending/base.rb +1 -13
  23. data/lib/mailhandler/sending/smtp.rb +20 -22
  24. data/lib/mailhandler/version.rb +2 -2
  25. data/mailhandler.gemspec +14 -17
  26. data/readme.md +33 -8
  27. data/spec/spec_helper.rb +1 -5
  28. data/spec/unit/mailhandler/receiver_spec.rb +8 -30
  29. data/spec/unit/mailhandler/receiving/base_spec.rb +4 -14
  30. data/spec/unit/mailhandler/receiving/folder_spec.rb +61 -155
  31. data/spec/unit/mailhandler/receiving/imap_spec.rb +18 -42
  32. data/spec/unit/mailhandler/receiving/notification/console_spec.rb +6 -16
  33. data/spec/unit/mailhandler/receiving/notification/email/content_spec.rb +10 -44
  34. data/spec/unit/mailhandler/receiving/notification/email_spec.rb +9 -15
  35. data/spec/unit/mailhandler/sender_spec.rb +12 -23
  36. data/spec/unit/mailhandler/sending/sender_api_batch_spec.rb +7 -19
  37. data/spec/unit/mailhandler/sending/sender_api_spec.rb +4 -14
  38. data/spec/unit/mailhandler/sending/sender_smtp_spec.rb +24 -6
  39. data/spec/unit/mailhandler_spec.rb +33 -25
  40. metadata +2 -2
@@ -2,107 +2,65 @@ require_relative '../base'
2
2
  require_relative '../../../errors'
3
3
 
4
4
  module MailHandler
5
-
6
5
  module Receiving
7
-
8
6
  class FileList
9
-
10
7
  module Filter
11
-
12
8
  class Base
13
-
14
9
  attr_accessor :files, :fast_check
15
10
 
16
11
  def initialize(files)
17
-
18
- @files=files
19
-
12
+ @files = files
20
13
  end
21
14
 
22
15
  def get
23
-
24
16
  files.select { |file| ignore_exception { meets_expectation?(file) } }
25
-
26
17
  end
27
18
 
28
19
  protected
29
20
 
30
- def meet_expectation?(file)
31
-
21
+ def meet_expectation?(_file)
32
22
  raise MailHandler::InterfaceError, 'Interface not implemented.'
33
-
34
23
  end
35
24
 
36
25
  def read_file(file)
37
-
38
26
  File.read(file)
39
-
40
27
  end
41
28
 
42
29
  private
43
30
 
44
31
  def ignore_exception
45
-
46
- begin
47
-
48
- yield
49
-
50
- rescue
51
-
52
- false
53
-
54
- end
55
-
32
+ yield
33
+ rescue StandardError
34
+ false
56
35
  end
57
-
58
36
  end
59
37
 
60
38
  module ByDate
61
39
 
62
- class Since < Base
63
-
40
+ class BaseDate < Base
64
41
  def initialize(files, date)
65
-
66
42
  super(files)
67
43
  @date = date
68
-
69
44
  end
45
+ end
70
46
 
47
+ class Since < BaseDate
71
48
  private
72
49
 
73
50
  def meets_expectation?(file)
74
-
75
- (File.exists? file)? (File.ctime file) > @date : false
76
-
51
+ File.exist?(file)? (File.ctime file) > @date : false
77
52
  end
78
-
79
53
  end
80
54
 
81
55
  class Before < Base
82
-
83
- def initialize(files, date)
84
-
85
- super(files)
86
- @date = date
87
-
88
- end
89
-
90
56
  private
91
57
 
92
58
  def meets_expectation?(file)
93
-
94
- (File.exists? file)? (File.ctime file) < @date : false
95
-
59
+ File.exist?(file)? (File.ctime file) < @date : false
96
60
  end
97
-
98
61
  end
99
-
100
62
  end
101
-
102
63
  end
103
-
104
64
  end
105
-
106
65
  end
107
-
108
66
  end
@@ -2,72 +2,50 @@ require 'mail'
2
2
  require_relative 'base'
3
3
 
4
4
  module MailHandler
5
-
6
5
  module Receiving
7
-
8
6
  class FileList
9
-
10
7
  module Filter
11
-
12
8
  # filtering file content by its email properties
13
9
  class Email < Base
14
-
15
10
  def initialize(files)
16
-
17
- @fast_check=true
11
+ @fast_check = true
18
12
  super(files)
19
-
20
13
  end
21
14
 
22
15
  protected
23
16
 
24
17
  def read_email_from_file(file)
25
-
26
18
  Mail.read(file)
27
-
28
19
  end
29
20
 
30
21
  def meets_expectation?(file)
31
-
32
22
  # fast content checks search for content by file reading
33
23
  # slow content checks search for content by reconstructing email from file and then searching for content
34
- (fast_check)? check_content_fast(file) : check_content_slow(file)
35
-
24
+ fast_check ? check_content_fast(file) : check_content_slow(file)
36
25
  end
37
26
 
38
- def check_content_fast(file)
39
-
27
+ def check_content_fast(_file)
40
28
  raise MailHandler::InterfaceError, 'Interface not implemented.'
41
-
42
29
  end
43
30
 
44
- def check_content_slow(file)
45
-
31
+ def check_content_slow(_file)
46
32
  raise MailHandler::InterfaceError, 'Interface not implemented.'
47
-
48
33
  end
49
-
50
34
  end
51
35
 
52
36
  class ByEmailContent < Email
53
-
54
37
  def initialize(files, content)
55
-
56
38
  super(files)
57
39
  @content = content
58
-
59
40
  end
60
41
 
61
42
  private
62
43
 
63
44
  def check_content_fast(file)
64
-
65
45
  read_file(file).include? @content
66
-
67
46
  end
68
47
 
69
48
  def check_content_slow(file)
70
-
71
49
  email = read_email_from_file(file)
72
50
 
73
51
  if email.multipart?
@@ -79,52 +57,34 @@ module MailHandler
79
57
  email.decoded.include? @content
80
58
 
81
59
  end
82
-
83
60
  end
84
-
85
61
  end
86
62
 
87
63
  class ByEmailSubject < ByEmailContent
88
-
89
64
  private
90
65
 
91
66
  def check_content_fast(file)
92
-
93
67
  read_file(file).include? @content
94
-
95
68
  end
96
69
 
97
70
  def check_content_slow(file)
98
-
99
71
  read_email_from_file(file).subject.to_s.include? @content
100
-
101
72
  end
102
-
103
73
  end
104
74
 
105
75
  class ByEmailRecipient < Email
106
-
107
76
  def initialize(files, recipient)
108
-
109
77
  super(files)
110
78
  @recipient = recipient
111
-
112
79
  end
113
80
 
114
81
  private
115
82
 
116
83
  def meets_expectation?(file)
117
-
118
84
  read_email_from_file(file)[@recipient.keys.first].to_s.include? @recipient.values.first
119
-
120
85
  end
121
-
122
86
  end
123
-
124
87
  end
125
-
126
88
  end
127
-
128
89
  end
129
-
130
90
  end
@@ -6,11 +6,8 @@ require_relative 'filelist/filter/base.rb'
6
6
  require_relative 'filelist/filter/email.rb'
7
7
 
8
8
  module MailHandler
9
-
10
9
  module Receiving
11
-
12
10
  class FolderChecker < Checker
13
-
14
11
  include FileHandling
15
12
 
16
13
  # folders in which emails will be searched for and managed
@@ -18,36 +15,28 @@ module MailHandler
18
15
  :archive_folder
19
16
 
20
17
  def initialize(inbox_folder = nil, archive_folder = nil)
21
-
22
18
  super()
23
19
 
24
20
  @inbox_folder = inbox_folder
25
21
  @archive_folder = archive_folder
26
-
27
22
  end
28
23
 
29
24
  # check whether email is received by checking for an email in folder
30
25
  def find(options)
31
-
32
26
  verify_and_set_search_options(options)
33
27
  verify_mailbox_folders
34
28
  email_files = find_files(search_options)
35
29
 
36
30
  unless email_files.empty?
37
-
38
31
  @found_emails = parse_email_from_files(email_files, search_options[:count])
39
32
  move_files(email_files) if search_options[:archive]
40
-
41
33
  end
42
34
 
43
35
  search_result
44
-
45
36
  end
46
37
 
47
38
  def start
48
-
49
39
  verify_mailbox_folders
50
-
51
40
  end
52
41
 
53
42
  private
@@ -55,94 +44,67 @@ module MailHandler
55
44
  # filter options which need to be done by searching files
56
45
  FILE_SEARCH_CLASSES = {
57
46
 
58
- :by_subject => FileList::Filter::ByEmailSubject,
59
- :by_content => FileList::Filter::ByEmailContent,
60
- :since => FileList::Filter::ByDate::Since,
61
- :before => FileList::Filter::ByDate::Before,
62
- :by_recipient => FileList::Filter::ByEmailRecipient
63
- }
47
+ by_subject: FileList::Filter::ByEmailSubject,
48
+ by_content: FileList::Filter::ByEmailContent,
49
+ since: FileList::Filter::ByDate::Since,
50
+ before: FileList::Filter::ByDate::Before,
51
+ by_recipient: FileList::Filter::ByEmailRecipient
52
+ }.freeze
64
53
 
65
54
  def search_pattern
66
-
67
55
  @inbox_folder + '/*.*'
68
-
69
56
  end
70
57
 
71
58
  # find files by FILE_SEARCH_CLASSES options
72
59
  # this will ignore filter criteria options which can't be done on files directly
73
60
  def find_files(options)
74
-
75
61
  file_list = FileList.new
76
62
  files = filter_files(file_list.get(search_pattern), options)
77
63
  file_list.sort(files)
78
-
79
64
  end
80
65
 
81
66
  def filter_files(files, options)
82
-
83
67
  options.each do |key, value|
68
+ next if FILE_SEARCH_CLASSES[key].nil?
84
69
 
85
- if FILE_SEARCH_CLASSES[key] != nil
86
-
87
- filter = FILE_SEARCH_CLASSES[key].new(files, value)
88
- filter.fast_check = options[:fast_check] unless options[:fast_check].nil?
89
- files = filter.get
90
-
91
- end
92
-
70
+ filter = FILE_SEARCH_CLASSES[key].new(files, value)
71
+ filter.fast_check = options[:fast_check] unless options[:fast_check].nil?
72
+ files = filter.get
93
73
  end
94
74
 
95
75
  files
96
-
97
76
  end
98
77
 
99
78
  def move_files(files)
100
-
101
- files.each { |file| (inbox_folder == archive_folder)? delete_file(file) : archive_file(file) }
102
-
79
+ files.each { |file| (inbox_folder == archive_folder) ? delete_file(file) : archive_file(file) }
103
80
  end
104
81
 
105
82
  def parse_email_from_files(files, count)
106
-
107
83
  read_files(files, count).map { |email_string| Mail.read_from_string(email_string) }
108
-
109
84
  end
110
85
 
111
86
  def read_files(files, count)
112
-
113
87
  file_contents = []
114
88
  files.first(count).each do |file|
115
-
116
- file_content = access_file(file, nil) { File.read(file ) }
89
+ file_content = access_file(file, nil) { File.read(file) }
117
90
  file_contents << file_content unless file_content.nil?
118
-
119
91
  end
120
92
 
121
93
  file_contents
122
-
123
94
  end
124
95
 
125
96
  def archive_file(file)
126
-
127
97
  access_file(file) { FileUtils.mv("#{inbox_folder}/#{File.basename(file)}", "#{archive_folder}/#{File.basename(file)}") }
128
-
129
98
  end
130
99
 
131
100
  def delete_file(file)
132
-
133
- access_file(file) { FileUtils.rm_r "#{inbox_folder}/#{File.basename(file)}", :force => false }
134
-
101
+ access_file(file) { FileUtils.rm_r "#{inbox_folder}/#{File.basename(file)}", force: false }
135
102
  end
136
103
 
137
104
  def verify_mailbox_folders
138
-
139
- raise MailHandler::Error, 'Folder variables are not set.' if inbox_folder.nil? or archive_folder.nil?
140
- raise MailHandler::FileError, 'Mailbox folders do not exist.' unless File.directory? inbox_folder and File.directory? archive_folder
141
-
105
+ raise MailHandler::Error, 'Folder variables are not set.' if inbox_folder.nil? || archive_folder.nil?
106
+ raise MailHandler::FileError, 'Mailbox folders do not exist.' unless File.directory?(inbox_folder) && File.directory?(archive_folder)
142
107
  end
143
-
144
108
  end
145
-
146
109
  end
147
-
148
- end
110
+ end
@@ -1,15 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  require 'mail'
4
2
  require_relative 'base.rb'
5
3
  require_relative '../errors'
6
4
 
7
5
  module MailHandler
8
-
9
6
  module Receiving
10
-
11
7
  class IMAPChecker < Checker
12
-
13
8
  attr_accessor :address,
14
9
  :port,
15
10
  :username,
@@ -22,83 +17,61 @@ module MailHandler
22
17
  attr_accessor :manual_connection_manage
23
18
 
24
19
  def initialize
25
-
26
20
  super
27
21
  @manual_connection_manage = false
28
22
  @available_search_options = AVAILABLE_SEARCH_OPTIONS
29
-
30
23
  end
31
24
 
32
25
  def find(options)
33
-
34
26
  verify_and_set_search_options(options)
35
27
  @found_emails = find_emails(search_options)
36
28
 
37
29
  search_result
38
-
39
30
  end
40
31
 
41
32
  def start
42
-
43
33
  unless manual_connection_manage
44
34
  init_retriever
45
35
  connect
46
36
  end
47
-
48
37
  end
49
38
 
50
39
  def stop
51
-
52
- unless manual_connection_manage
53
- disconnect
54
- end
55
-
40
+ disconnect unless manual_connection_manage
56
41
  end
57
42
 
58
43
  def connect
59
-
60
44
  mailer.connect
61
-
62
45
  end
63
46
 
64
47
  def disconnect
65
-
66
48
  mailer.disconnect unless mailer.imap_connection.disconnected?
67
-
68
49
  end
69
50
 
70
51
  # delegate retrieval details to Mail library
71
52
  def init_retriever
72
-
73
53
  # set imap settings if they are not set
74
54
  unless retriever_set?
75
55
 
76
56
  imap_settings = retriever_settings
77
57
 
78
58
  Mail.defaults do
79
-
80
59
  retriever_method :imap,
81
60
  imap_settings
82
-
83
61
  end
84
62
 
85
63
  end
86
-
87
64
  end
88
65
 
89
66
  private
90
67
 
91
68
  def mailer
92
-
93
69
  @mailer ||= Mail.retriever_method
94
-
95
70
  end
96
71
 
97
72
  def reconnect
98
-
99
73
  disconnect
100
74
  connect
101
-
102
75
  end
103
76
 
104
77
  # search options:
@@ -107,55 +80,46 @@ module MailHandler
107
80
  # count - Int, number of found emails to return
108
81
  # archive - Boolean
109
82
  # by_recipient - Hash, accepts a hash like: :to => 'igor@example.com'
110
- AVAILABLE_SEARCH_OPTIONS = [
111
-
112
- :by_subject,
113
- :by_content,
114
- :since,
115
- :before,
116
- :count,
117
- :archive,
118
- :by_recipient,
119
- :fast_check
120
-
121
- ]
83
+ AVAILABLE_SEARCH_OPTIONS = %i[
84
+
85
+ by_subject
86
+ by_content
87
+ since
88
+ before
89
+ count
90
+ archive
91
+ by_recipient
92
+ fast_check
93
+ ].freeze
122
94
 
123
95
  RETRY_ON_ERROR_COUNT = 3
124
96
 
125
97
  def retriever_set?
126
-
127
98
  Mail.retriever_method.settings == retriever_settings
128
-
129
99
  end
130
100
 
131
101
  def retriever_settings
132
-
133
102
  {
134
- :address => address,
135
- :port => port,
136
- :user_name => username,
137
- :password => password,
138
- :authentication => authentication,
139
- :enable_ssl => use_ssl
103
+ address: address,
104
+ port: port,
105
+ user_name: username,
106
+ password: password,
107
+ authentication: authentication,
108
+ enable_ssl: use_ssl
140
109
  }
141
-
142
110
  end
143
111
 
144
112
  def find_emails(options)
145
-
146
113
  imap_search(RETRY_ON_ERROR_COUNT, options)
147
-
148
114
  end
149
115
 
150
116
  def imap_search(retry_count, options)
151
-
152
- result = mailer.find_emails(:what => :last, :count => search_options[:count], :order => :desc, :keys => imap_filter_keys(options), :delete_after_find => options[:archive])
153
- (result.kind_of? Array)? result : [result]
117
+ result = mailer.find_emails(what: :last, count: search_options[:count], order: :desc, keys: imap_filter_keys(options), delete_after_find: options[:archive])
118
+ result.is_a? Array ? result : [result]
154
119
 
155
120
  # Silently ignore IMAP search errors, [RETRY_ON_ERROR_COUNT] times
156
121
  rescue Net::IMAP::ResponseError, EOFError, NoMethodError => e
157
-
158
- if (retry_count -=1) >= 0
122
+ if (retry_count -= 1) >= 0
159
123
 
160
124
  puts e
161
125
  reconnect
@@ -166,51 +130,43 @@ module MailHandler
166
130
  raise e
167
131
 
168
132
  end
169
-
170
133
  end
171
134
 
172
135
  def imap_filter_keys(options)
173
-
174
136
  keys = []
175
137
 
176
138
  options.keys.each do |filter_option|
177
-
178
139
  case filter_option
179
140
 
180
- when :by_recipient
141
+ when :by_recipient
181
142
 
182
- keys << options[:by_recipient].keys.first.to_s.upcase << options[:by_recipient].values.first
143
+ keys << options[:by_recipient].keys.first.to_s.upcase << options[:by_recipient].values.first
183
144
 
184
- when :by_subject
145
+ when :by_subject
185
146
 
186
- keys << 'SUBJECT' << options[:by_subject].to_s
147
+ keys << 'SUBJECT' << options[:by_subject].to_s
187
148
 
188
- when :by_content
149
+ when :by_content
189
150
 
190
- keys << 'BODY' << options[:by_content].to_s
151
+ keys << 'BODY' << options[:by_content].to_s
191
152
 
192
- when :since
153
+ when :since
193
154
 
194
- keys << 'SINCE' << Net::IMAP.format_date(options[:since])
155
+ keys << 'SINCE' << Net::IMAP.format_date(options[:since])
195
156
 
196
- when :before
157
+ when :before
197
158
 
198
- keys << 'BEFORE' << Net::IMAP.format_date(options[:before])
159
+ keys << 'BEFORE' << Net::IMAP.format_date(options[:before])
199
160
 
200
- else
161
+ else
201
162
 
202
- # do nothing
163
+ # do nothing
203
164
 
204
165
  end
205
-
206
166
  end
207
167
 
208
- (keys.empty?)? nil : keys
209
-
168
+ keys.empty? ? nil : keys
210
169
  end
211
-
212
170
  end
213
-
214
171
  end
215
-
216
172
  end