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.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/Rakefile +2 -2
- data/lib/mailhandler.rb +13 -37
- data/lib/mailhandler/errors.rb +1 -5
- data/lib/mailhandler/receiver.rb +4 -22
- data/lib/mailhandler/receiving/base.rb +16 -45
- data/lib/mailhandler/receiving/filelist/base.rb +25 -49
- data/lib/mailhandler/receiving/filelist/filter/base.rb +10 -52
- data/lib/mailhandler/receiving/filelist/filter/email.rb +4 -44
- data/lib/mailhandler/receiving/folder.rb +16 -54
- data/lib/mailhandler/receiving/imap.rb +34 -78
- data/lib/mailhandler/receiving/mail.rb +5 -19
- data/lib/mailhandler/receiving/notification/console.rb +2 -18
- data/lib/mailhandler/receiving/notification/email.rb +5 -28
- data/lib/mailhandler/receiving/notification/email/content.rb +9 -20
- data/lib/mailhandler/receiving/notification/email/states.rb +1 -36
- data/lib/mailhandler/receiving/observer.rb +5 -16
- data/lib/mailhandler/sender.rb +2 -14
- data/lib/mailhandler/sending/api.rb +1 -7
- data/lib/mailhandler/sending/api_batch.rb +1 -13
- data/lib/mailhandler/sending/base.rb +1 -13
- data/lib/mailhandler/sending/smtp.rb +20 -22
- data/lib/mailhandler/version.rb +2 -2
- data/mailhandler.gemspec +14 -17
- data/readme.md +33 -8
- data/spec/spec_helper.rb +1 -5
- data/spec/unit/mailhandler/receiver_spec.rb +8 -30
- data/spec/unit/mailhandler/receiving/base_spec.rb +4 -14
- data/spec/unit/mailhandler/receiving/folder_spec.rb +61 -155
- data/spec/unit/mailhandler/receiving/imap_spec.rb +18 -42
- data/spec/unit/mailhandler/receiving/notification/console_spec.rb +6 -16
- data/spec/unit/mailhandler/receiving/notification/email/content_spec.rb +10 -44
- data/spec/unit/mailhandler/receiving/notification/email_spec.rb +9 -15
- data/spec/unit/mailhandler/sender_spec.rb +12 -23
- data/spec/unit/mailhandler/sending/sender_api_batch_spec.rb +7 -19
- data/spec/unit/mailhandler/sending/sender_api_spec.rb +4 -14
- data/spec/unit/mailhandler/sending/sender_smtp_spec.rb +24 -6
- data/spec/unit/mailhandler_spec.rb +33 -25
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f4daed68e55b824dbcad5321f41fd3aa4374769
|
4
|
+
data.tar.gz: 12934cc4aa8d94d6647c2049291f40910b939a7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f3f94f0de2600cc2d99d8cfeeb43f3b33ec74e5917a0a045b103f0f2c63ccb52ecdcc1bd0a77300ea13de5f8820d834c679edfc6e955a01754d2dcf72a95f09
|
7
|
+
data.tar.gz: 23355aac8afd26e73c3f04b34a75dd65d823e78cdf8f95cce040df3482a5cf1f14c18d276726b42df23d86eb626a44b58bd26c716cc42fd65b3de2c9fb0caf33
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
2
|
require 'rspec/core/rake_task'
|
3
|
-
RSpec::Core::RakeTask.new(:default)
|
3
|
+
RSpec::Core::RakeTask.new(:default)
|
data/lib/mailhandler.rb
CHANGED
@@ -8,31 +8,26 @@ require_relative 'mailhandler/errors'
|
|
8
8
|
# Main MailHandler class, for creating sender and receiver objects.
|
9
9
|
# Sender objects for sending emails, receiver objects for searching and receiving emails.
|
10
10
|
module MailHandler
|
11
|
-
|
12
|
-
extend self
|
11
|
+
module_function
|
13
12
|
|
14
13
|
# sending accessor
|
15
14
|
# @return [Object] - sender for sending emails
|
16
15
|
def sender(type = :postmark_api)
|
17
|
-
|
18
16
|
handler = Handler.new
|
19
17
|
handler.init_sender(type)
|
20
18
|
yield(handler.sender.dispatcher) if block_given?
|
21
19
|
|
22
20
|
handler.sender
|
23
|
-
|
24
21
|
end
|
25
22
|
|
26
23
|
# receiving accessor
|
27
24
|
# @return [Object] - receiver for searching emails
|
28
25
|
def receiver(type = :folder, notifications = [])
|
29
|
-
|
30
26
|
handler = Handler.new
|
31
27
|
handler.init_receiver(type, notifications)
|
32
28
|
yield(handler.receiver.checker) if block_given?
|
33
29
|
|
34
30
|
handler.receiver
|
35
|
-
|
36
31
|
end
|
37
32
|
|
38
33
|
# Holder for receiving and sending handlers
|
@@ -40,92 +35,73 @@ module MailHandler
|
|
40
35
|
# @param [Receiving::Class] receiver
|
41
36
|
# @param [Sending::Class] sender
|
42
37
|
def handler(receiver, sender)
|
43
|
-
|
44
38
|
handler = Handler.new
|
45
39
|
handler.handler(receiver, sender)
|
46
|
-
|
47
40
|
end
|
48
41
|
|
49
42
|
# main handler class for creating sender, receiver handlers
|
50
43
|
class Handler
|
51
|
-
|
52
44
|
attr_accessor :sender,
|
53
45
|
:receiver
|
54
46
|
|
55
47
|
def init_sender(type = :postmark_api)
|
56
|
-
|
57
48
|
verify_type(type, SENDER_TYPES)
|
58
49
|
@sender = MailHandler::Sender.new(SENDER_TYPES[type].new)
|
59
|
-
|
60
50
|
end
|
61
51
|
|
62
|
-
|
63
52
|
def init_receiver(type = :folder, notifications = [])
|
64
|
-
|
65
53
|
verify_type(type, CHECKER_TYPES)
|
66
54
|
@receiver = MailHandler::Receiver.new(CHECKER_TYPES[type].new)
|
67
55
|
add_receiving_notifications(@receiver, notifications)
|
68
56
|
@receiver
|
69
|
-
|
70
57
|
end
|
71
58
|
|
72
59
|
def handler(sender, receiver)
|
73
|
-
|
74
60
|
handler = new
|
75
61
|
handler.sender = sender
|
76
62
|
handler.receiver = receiver
|
77
63
|
handler
|
78
|
-
|
79
64
|
end
|
80
65
|
|
81
66
|
private
|
82
67
|
|
83
|
-
# Add notifications, in case email receiving is delayed.
|
68
|
+
# Add notifications, in case email receiving is delayed.
|
84
69
|
# When email is delayed, email notification can be sent or console status update.
|
85
70
|
#
|
86
71
|
# @param [Receiving::Object] receiver
|
87
72
|
# @param [Array<Receiving::Notification::Class>] notifications
|
88
73
|
def add_receiving_notifications(receiver, notifications)
|
89
|
-
|
90
74
|
if (notifications - NOTIFICATION_TYPES.keys).empty?
|
91
75
|
|
92
76
|
notifications.each { |n| receiver.add_observer(NOTIFICATION_TYPES[n].new) }
|
93
77
|
|
94
78
|
end
|
95
|
-
|
96
79
|
end
|
97
80
|
|
98
81
|
def verify_type(type, types)
|
99
|
-
|
100
|
-
raise MailHandler::TypeError, "Unknown type - #{type}, possible options: #{types.keys}." unless types.keys.include? type
|
101
|
-
|
82
|
+
raise MailHandler::TypeError, "Unknown type - #{type}, possible options: #{types.keys}." unless types.key?(type)
|
102
83
|
end
|
103
84
|
|
104
85
|
CHECKER_TYPES = {
|
105
86
|
|
106
|
-
|
107
|
-
|
87
|
+
folder: Receiving::FolderChecker,
|
88
|
+
imap: Receiving::IMAPChecker
|
108
89
|
|
109
|
-
}
|
90
|
+
}.freeze
|
110
91
|
|
111
92
|
SENDER_TYPES = {
|
112
93
|
|
113
|
-
|
114
|
-
|
115
|
-
|
94
|
+
postmark_api: Sending::PostmarkAPISender,
|
95
|
+
postmark_batch_api: Sending::PostmarkBatchAPISender,
|
96
|
+
smtp: Sending::SMTPSender
|
116
97
|
|
117
|
-
}
|
98
|
+
}.freeze
|
118
99
|
|
119
100
|
NOTIFICATION_TYPES = {
|
120
101
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
}
|
102
|
+
console: Receiving::Notification::Console,
|
103
|
+
email: Receiving::Notification::Email
|
125
104
|
|
105
|
+
}.freeze
|
126
106
|
end
|
127
|
-
|
128
107
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
data/lib/mailhandler/errors.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
module MailHandler
|
2
|
-
|
3
2
|
class Error < StandardError
|
4
|
-
|
5
3
|
def initialize(message = nil)
|
6
4
|
super(message)
|
7
5
|
end
|
8
|
-
|
9
6
|
end
|
10
7
|
|
11
8
|
class UnknownError < Error; end
|
12
9
|
class TypeError < Error; end
|
13
10
|
class FileError < Error; end
|
14
11
|
class InterfaceError < Error; end
|
15
|
-
|
16
|
-
end
|
12
|
+
end
|
data/lib/mailhandler/receiver.rb
CHANGED
@@ -4,9 +4,7 @@ require_relative 'receiving/observer'
|
|
4
4
|
require_relative 'receiving/mail.rb'
|
5
5
|
|
6
6
|
module MailHandler
|
7
|
-
|
8
7
|
class Receiver
|
9
|
-
|
10
8
|
include Receiving::Observer
|
11
9
|
|
12
10
|
attr_accessor :checker,
|
@@ -15,10 +13,8 @@ module MailHandler
|
|
15
13
|
:search_frequency
|
16
14
|
|
17
15
|
module DEFAULTS
|
18
|
-
|
19
16
|
MAX_SEARCH_DURATION = 240 # maximum time for search to last in [seconds]
|
20
17
|
SEARCH_FREQUENCY = 0.5 # how frequently to check for email in inbox [seconds]
|
21
|
-
|
22
18
|
end
|
23
19
|
|
24
20
|
# @param [Hash] - search options
|
@@ -31,18 +27,15 @@ module MailHandler
|
|
31
27
|
# @param [boolean] - result of search
|
32
28
|
# @param [Mail] - first email found
|
33
29
|
# @param [Array] - all emails found
|
34
|
-
Search = Struct.new(
|
30
|
+
Search = Struct.new(:options, :started_at, :finished_at, :duration, :max_duration, :result, :email, :emails)
|
35
31
|
|
36
32
|
def initialize(checker)
|
37
|
-
|
38
33
|
@checker = checker
|
39
34
|
@max_search_duration = DEFAULTS::MAX_SEARCH_DURATION
|
40
35
|
@search_frequency = DEFAULTS::SEARCH_FREQUENCY
|
41
|
-
|
42
36
|
end
|
43
37
|
|
44
38
|
def find_email(options)
|
45
|
-
|
46
39
|
init_search_details(options)
|
47
40
|
checker.start
|
48
41
|
|
@@ -58,40 +51,29 @@ module MailHandler
|
|
58
51
|
|
59
52
|
notify_observers(search)
|
60
53
|
checker.search_result
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
checker.stop
|
65
|
-
|
54
|
+
ensure
|
55
|
+
checker.stop
|
66
56
|
end
|
67
57
|
|
68
58
|
private
|
69
59
|
|
70
60
|
def init_search_details(options)
|
71
|
-
|
72
61
|
@search = Search.new
|
73
62
|
@search.options = options
|
74
63
|
@search.started_at = Time.now
|
75
64
|
@search.max_duration = @max_search_duration
|
76
|
-
|
77
65
|
end
|
78
66
|
|
79
67
|
def update_search_details
|
80
|
-
|
81
68
|
search.finished_at = Time.now
|
82
69
|
search.duration = search.finished_at - search.started_at
|
83
70
|
search.result = checker.search_result
|
84
71
|
search.emails = checker.found_emails
|
85
72
|
search.email = search.emails.first
|
86
|
-
|
87
73
|
end
|
88
74
|
|
89
75
|
def search_time_expired?
|
90
|
-
|
91
76
|
(Time.now - search.started_at) > @max_search_duration
|
92
|
-
|
93
77
|
end
|
94
|
-
|
95
78
|
end
|
96
|
-
|
97
|
-
end
|
79
|
+
end
|
@@ -1,83 +1,64 @@
|
|
1
1
|
require_relative '../errors'
|
2
2
|
|
3
3
|
module MailHandler
|
4
|
-
|
5
4
|
module Receiving
|
6
|
-
|
7
5
|
#
|
8
6
|
# Email receiving checker main class.
|
9
7
|
# @see MailHandler::Receiving::FolderChecker for example for one of implemented checkers.
|
10
8
|
#
|
11
9
|
class Checker
|
12
|
-
|
13
10
|
attr_accessor :search_options,
|
14
11
|
:found_emails,
|
15
12
|
:available_search_options
|
16
13
|
|
17
14
|
def initialize
|
18
|
-
|
19
15
|
@available_search_options = AVAILABLE_SEARCH_OPTIONS
|
20
16
|
set_base_search_options
|
21
17
|
reset_found_emails
|
22
|
-
|
23
18
|
end
|
24
19
|
|
25
|
-
def start
|
26
|
-
|
27
|
-
end
|
20
|
+
def start; end
|
28
21
|
|
29
|
-
def stop
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
def find(options)
|
22
|
+
def stop; end
|
34
23
|
|
24
|
+
def find(_options)
|
35
25
|
raise MailHandler::InterfaceError, 'Find interface not implemented.'
|
36
|
-
|
37
26
|
end
|
38
27
|
|
39
28
|
def search_result
|
40
|
-
|
41
29
|
!found_emails.empty?
|
42
|
-
|
43
30
|
end
|
44
31
|
|
45
32
|
def reset_found_emails
|
46
|
-
|
47
33
|
@found_emails = []
|
48
|
-
|
49
34
|
end
|
50
35
|
|
51
36
|
private
|
52
37
|
|
53
|
-
AVAILABLE_SEARCH_OPTIONS = [
|
38
|
+
AVAILABLE_SEARCH_OPTIONS = %i[
|
54
39
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
]
|
40
|
+
by_subject
|
41
|
+
by_content
|
42
|
+
since
|
43
|
+
before
|
44
|
+
by_recipient
|
45
|
+
count
|
46
|
+
archive
|
47
|
+
fast_check
|
48
|
+
].freeze
|
65
49
|
|
66
50
|
protected
|
67
51
|
|
68
52
|
def verify_and_set_search_options(options)
|
69
|
-
|
70
53
|
validate_used_options(options)
|
71
54
|
validate_option_values(options)
|
72
55
|
|
73
56
|
set_base_search_options
|
74
57
|
add_additional_search_options(options)
|
75
58
|
reset_found_emails
|
76
|
-
|
77
59
|
end
|
78
60
|
|
79
61
|
def validate_option_values(options)
|
80
|
-
|
81
62
|
if options[:since]
|
82
63
|
|
83
64
|
raise MailHandler::Error, "Incorrect option options[:since]=#{options[:since]}." unless options[:since].is_a? Time
|
@@ -87,13 +68,13 @@ module MailHandler
|
|
87
68
|
unless options[:count].nil?
|
88
69
|
|
89
70
|
count = options[:count]
|
90
|
-
raise MailHandler::Error, "Incorrect option options[:count]=#{options[:count]}." if count < 0
|
71
|
+
raise MailHandler::Error, "Incorrect option options[:count]=#{options[:count]}." if (count < 0) || (count > 2000)
|
91
72
|
|
92
73
|
end
|
93
74
|
|
94
75
|
if options[:archive]
|
95
76
|
|
96
|
-
raise MailHandler::Error, "Incorrect option options[:archive]=#{options[:archive]}." unless options[:archive] == true
|
77
|
+
raise MailHandler::Error, "Incorrect option options[:archive]=#{options[:archive]}." unless (options[:archive] == true) || (options[:archive] == false)
|
97
78
|
|
98
79
|
end
|
99
80
|
|
@@ -102,32 +83,22 @@ module MailHandler
|
|
102
83
|
raise MailHandler::Error, "Incorrect option options[:by_recipient]=#{options[:by_recipient]}." unless options[:by_recipient].is_a?(Hash)
|
103
84
|
|
104
85
|
end
|
105
|
-
|
106
86
|
end
|
107
87
|
|
108
88
|
def validate_used_options(options)
|
109
|
-
|
110
89
|
unless (options.keys - available_search_options).empty?
|
111
90
|
raise MailHandler::Error, "#{(options.keys - available_search_options)} - Incorrect search option values, options are #{available_search_options}."
|
112
91
|
end
|
113
|
-
|
114
92
|
end
|
115
93
|
|
116
94
|
def set_base_search_options
|
117
|
-
|
118
95
|
# Default number of email results to return, and whether to archive emails.
|
119
|
-
@search_options = {:
|
120
|
-
|
96
|
+
@search_options = { count: 50, archive: false }
|
121
97
|
end
|
122
98
|
|
123
99
|
def add_additional_search_options(options)
|
124
|
-
|
125
100
|
@search_options = @search_options.merge options
|
126
|
-
|
127
101
|
end
|
128
|
-
|
129
102
|
end
|
130
|
-
|
131
103
|
end
|
132
|
-
|
133
104
|
end
|
@@ -4,25 +4,17 @@ require 'fileutils'
|
|
4
4
|
# Patterns to be used can be checked here: http://ruby-doc.org/core-1.9.3/Dir.html
|
5
5
|
|
6
6
|
module MailHandler
|
7
|
-
|
8
7
|
module Receiving
|
9
|
-
|
10
8
|
module FileHandling
|
11
|
-
|
12
9
|
# if file exists, execute file operation, otherwise return default return value when it doesn't
|
13
|
-
def access_file(file, default_return = false
|
14
|
-
|
15
|
-
if File.exists? file
|
10
|
+
def access_file(file, default_return = false)
|
11
|
+
if File.exist? file
|
16
12
|
|
17
13
|
begin
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
rescue => e
|
22
|
-
|
23
|
-
raise e if File.exists? file
|
14
|
+
yield
|
15
|
+
rescue StandardError => e
|
16
|
+
raise e if File.exist? file
|
24
17
|
default_return
|
25
|
-
|
26
18
|
end
|
27
19
|
|
28
20
|
else
|
@@ -30,69 +22,53 @@ module MailHandler
|
|
30
22
|
default_return
|
31
23
|
|
32
24
|
end
|
33
|
-
|
34
25
|
end
|
35
|
-
|
36
26
|
end
|
37
27
|
|
38
28
|
class FileList
|
39
|
-
|
40
29
|
include FileHandling
|
41
30
|
|
42
31
|
def get(pattern)
|
43
|
-
|
44
32
|
Dir.glob(pattern)
|
45
|
-
|
46
33
|
end
|
47
34
|
|
48
35
|
def sort(files)
|
49
|
-
|
50
36
|
swapped = true
|
51
37
|
j = 0
|
52
38
|
|
53
|
-
while swapped
|
39
|
+
while swapped
|
54
40
|
|
55
41
|
swapped = false
|
56
|
-
j+=1
|
42
|
+
j += 1
|
57
43
|
|
58
44
|
(files.size - j).times do |i|
|
59
|
-
|
60
45
|
file1 = access_file(files[i], false) { File.new(files[i]).ctime }
|
61
|
-
file2 = access_file(files[i+1], false) { File.new(files[i+1]).ctime }
|
62
|
-
|
63
|
-
if file1 && file2 && file1 < file2
|
64
|
-
tmp = files[i]
|
65
|
-
files[i] = files[i + 1]
|
66
|
-
files[i + 1] = tmp
|
67
|
-
swapped = true
|
68
|
-
|
69
|
-
end
|
46
|
+
file2 = access_file(files[i + 1], false) { File.new(files[i + 1]).ctime }
|
70
47
|
|
48
|
+
next unless file1 && file2 && file1 < file2
|
49
|
+
tmp = files[i]
|
50
|
+
files[i] = files[i + 1]
|
51
|
+
files[i + 1] = tmp
|
52
|
+
swapped = true
|
71
53
|
end
|
72
54
|
|
73
55
|
end
|
74
56
|
|
75
57
|
files
|
76
|
-
|
77
58
|
end
|
78
|
-
|
79
59
|
end
|
80
|
-
|
81
60
|
end
|
82
|
-
|
83
61
|
end
|
84
62
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
FileList.
|
90
|
-
FileList::Filter::
|
91
|
-
FileList::Filter::
|
92
|
-
FileList::Filter::
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
=end
|
63
|
+
#
|
64
|
+
# TEST EXAMPLE
|
65
|
+
#
|
66
|
+
# FileList.get('*.*')
|
67
|
+
# FileList::Filter::ByEmailSubject.new(files,'subject').get
|
68
|
+
# FileList::Filter::ByEmailContent.new(files,'content').get
|
69
|
+
# FileList::Filter::ByEmailDate.new(files, date).get
|
70
|
+
# FileList::Filter::ByEmailRecipient.new(files, recipient).get
|
71
|
+
#
|
72
|
+
# f = FileList::Filter::ByEmailSubject.new(FileList.get("*.*"), "binding")
|
73
|
+
# puts f.get
|
74
|
+
#
|