mailhandler 1.0.36 → 1.0.37

Sign up to get free protection for your applications and to get access to all the features.
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