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
@@ -1,11 +1,8 @@
|
|
1
1
|
module Mail
|
2
|
-
|
3
2
|
class IMAP
|
4
|
-
|
5
3
|
attr_accessor :imap_connection
|
6
4
|
|
7
|
-
def find_emails(options={}, &block)
|
8
|
-
|
5
|
+
def find_emails(options = {}, &block)
|
9
6
|
options = validate_options(options)
|
10
7
|
options[:read_only] ? imap_connection.examine(options[:mailbox]) : imap_connection.select(options[:mailbox])
|
11
8
|
uids = imap_connection.uid_search(options[:keys])
|
@@ -13,12 +10,11 @@ module Mail
|
|
13
10
|
uids.reverse! if options[:what].to_sym == :last
|
14
11
|
uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
|
15
12
|
uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
|
16
|
-
|
13
|
+
(options[:what].to_sym != :last && options[:order].to_sym == :desc)
|
17
14
|
|
18
15
|
if block_given?
|
19
16
|
|
20
17
|
uids.each do |uid|
|
21
|
-
|
22
18
|
uid = options[:uid].to_i unless options[:uid].nil?
|
23
19
|
fetchdata = imap_connection.uid_fetch(uid, ['RFC822'])[0]
|
24
20
|
new_message = Mail.new(fetchdata.attr['RFC822'])
|
@@ -30,9 +26,8 @@ module Mail
|
|
30
26
|
yield new_message
|
31
27
|
end
|
32
28
|
|
33
|
-
imap_connection.uid_store(uid,
|
29
|
+
imap_connection.uid_store(uid, '+FLAGS', [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
|
34
30
|
break unless options[:uid].nil?
|
35
|
-
|
36
31
|
end
|
37
32
|
|
38
33
|
imap_connection.expunge if options[:delete_after_find]
|
@@ -42,25 +37,21 @@ module Mail
|
|
42
37
|
emails = []
|
43
38
|
|
44
39
|
uids.each do |uid|
|
45
|
-
|
46
40
|
uid = options[:uid].to_i unless options[:uid].nil?
|
47
41
|
fetchdata = imap_connection.uid_fetch(uid, ['RFC822'])[0]
|
48
42
|
emails << Mail.new(fetchdata.attr['RFC822'])
|
49
|
-
imap_connection.uid_store(uid,
|
43
|
+
imap_connection.uid_store(uid, '+FLAGS', [Net::IMAP::DELETED]) if options[:delete_after_find]
|
50
44
|
break unless options[:uid].nil?
|
51
|
-
|
52
45
|
end
|
53
46
|
|
54
47
|
imap_connection.expunge if options[:delete_after_find]
|
55
48
|
emails.size == 1 && options[:count] == 1 ? emails.first : emails
|
56
49
|
|
57
50
|
end
|
58
|
-
|
59
51
|
end
|
60
52
|
|
61
53
|
# Start an IMAP session
|
62
|
-
def connect(
|
63
|
-
|
54
|
+
def connect(_config = Mail::Configuration.instance)
|
64
55
|
@imap_connection = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
|
65
56
|
|
66
57
|
if settings[:authentication].nil?
|
@@ -70,19 +61,14 @@ module Mail
|
|
70
61
|
# (see also http://www.ensta.fr/~diam/ruby/online/ruby-doc-stdlib/libdoc/net/imap_connection/rdoc/classes/Net/IMAP.html#M000718)
|
71
62
|
imap_connection.authenticate(settings[:authentication], settings[:user_name], settings[:password])
|
72
63
|
end
|
73
|
-
|
74
64
|
end
|
75
65
|
|
76
66
|
def disconnect
|
77
|
-
|
78
67
|
if defined?(imap_connection) && imap_connection && !imap_connection.disconnected?
|
79
68
|
|
80
69
|
imap_connection.disconnect
|
81
70
|
|
82
71
|
end
|
83
|
-
|
84
72
|
end
|
85
|
-
|
86
73
|
end
|
87
|
-
|
88
74
|
end
|
@@ -1,44 +1,28 @@
|
|
1
1
|
module MailHandler
|
2
|
-
|
3
2
|
module Receiving
|
4
|
-
|
5
3
|
module Notification
|
6
|
-
|
7
4
|
class Console
|
8
|
-
|
9
5
|
def notify(search)
|
10
|
-
|
11
6
|
output_delay Time.now - search.started_at
|
12
|
-
|
13
7
|
end
|
14
8
|
|
15
9
|
private
|
16
10
|
|
17
11
|
module Seconds
|
18
|
-
|
19
12
|
TO_SHOW = 10
|
20
|
-
|
21
13
|
end
|
22
14
|
|
23
15
|
# print to screen delay length
|
24
16
|
def output_delay(delay)
|
25
|
-
|
26
17
|
delay_seconds = delay.to_i
|
27
|
-
output(delay_seconds) if [0,1].include? (delay_seconds % Seconds::TO_SHOW)
|
28
|
-
|
18
|
+
output(delay_seconds) if [0, 1].include? (delay_seconds % Seconds::TO_SHOW)
|
29
19
|
end
|
30
20
|
|
31
21
|
# print to screen delay length
|
32
22
|
def output(delay)
|
33
|
-
|
34
|
-
puts " email delay: #{'%03d' % delay} seconds"
|
35
|
-
|
23
|
+
puts " email delay: #{format('%03d', delay)} seconds"
|
36
24
|
end
|
37
|
-
|
38
25
|
end
|
39
|
-
|
40
26
|
end
|
41
|
-
|
42
27
|
end
|
43
|
-
|
44
28
|
end
|
@@ -3,22 +3,18 @@ require_relative 'email/states'
|
|
3
3
|
require_relative '../../errors'
|
4
4
|
|
5
5
|
module MailHandler
|
6
|
-
|
7
6
|
module Receiving
|
8
|
-
|
9
7
|
module Notification
|
10
|
-
|
11
8
|
class Email
|
12
|
-
|
13
|
-
attr_reader :sender,
|
9
|
+
attr_accessor :sender,
|
14
10
|
:from,
|
15
11
|
:contacts,
|
16
12
|
:min_time_to_notify,
|
17
|
-
:max_time_to_notify
|
18
|
-
:current_state
|
13
|
+
:max_time_to_notify
|
19
14
|
|
20
|
-
|
15
|
+
attr_reader :current_state
|
21
16
|
|
17
|
+
def initialize(sender, from, to, min_time_to_notify = 60)
|
22
18
|
@min_time_to_notify = min_time_to_notify
|
23
19
|
|
24
20
|
@sender = sender
|
@@ -26,29 +22,22 @@ module MailHandler
|
|
26
22
|
@contacts = to
|
27
23
|
init_state
|
28
24
|
set_content_handler(EmailContent.new)
|
29
|
-
|
30
25
|
end
|
31
26
|
|
32
27
|
def notify(search)
|
33
|
-
|
34
28
|
@max_time_to_notify = search.max_duration
|
35
29
|
init_state if Time.now - search.started_at < min_time_to_notify
|
36
30
|
@current_state.notify(search)
|
37
|
-
|
38
31
|
end
|
39
32
|
|
40
33
|
def set_state(state)
|
41
|
-
|
42
34
|
@current_state = state
|
43
|
-
|
44
35
|
end
|
45
36
|
|
46
37
|
def send_email(type, search)
|
47
|
-
|
48
38
|
verify_email_type(type)
|
49
39
|
content = @content_handler.retrieve(type, search.options, Time.now - search.started_at, from, contacts)
|
50
40
|
sender.send_email content
|
51
|
-
|
52
41
|
end
|
53
42
|
|
54
43
|
# Allow users to specify their own content classes.
|
@@ -57,30 +46,18 @@ module MailHandler
|
|
57
46
|
@content_handler = content_handler
|
58
47
|
end
|
59
48
|
|
60
|
-
|
61
49
|
private
|
62
50
|
|
63
51
|
def init_state
|
64
|
-
|
65
52
|
@current_state = Notification::NoDelay.new(self)
|
66
|
-
|
67
53
|
end
|
68
54
|
|
69
|
-
EMAIL_TYPES = [
|
55
|
+
EMAIL_TYPES = %i[delayed received].freeze
|
70
56
|
|
71
57
|
def verify_email_type(type)
|
72
|
-
|
73
58
|
raise MailHandler::TypeError, "Incorrect type: #{type}, allowed types: #{EMAIL_TYPES}." unless EMAIL_TYPES.include? type
|
74
|
-
|
75
59
|
end
|
76
|
-
|
77
60
|
end
|
78
|
-
|
79
61
|
end
|
80
|
-
|
81
62
|
end
|
82
|
-
|
83
63
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
@@ -1,52 +1,41 @@
|
|
1
1
|
require 'mail'
|
2
2
|
|
3
3
|
module MailHandler
|
4
|
-
|
5
4
|
module Receiving
|
6
|
-
|
7
5
|
module Notification
|
8
|
-
|
9
6
|
class EmailContent
|
10
|
-
|
11
7
|
# @param [Symbol] type - notification type
|
12
8
|
# @param [Hash] options - search options used for searching for an email
|
13
9
|
# @param [Int] delay - delay in seconds
|
14
10
|
# @param [String] from - email address
|
15
11
|
# @param [String] to - email address
|
16
12
|
def retrieve(type, options, delay, from, to)
|
17
|
-
|
18
13
|
mail = Mail.new
|
19
14
|
mail.from = from
|
20
15
|
mail.to = to
|
21
|
-
delay = (delay.to_f/60).round(2)
|
16
|
+
delay = (delay.to_f / 60).round(2)
|
22
17
|
|
23
18
|
case type
|
24
19
|
|
25
|
-
|
20
|
+
when :received
|
26
21
|
|
27
|
-
|
28
|
-
|
22
|
+
mail.subject = "Received - delay was #{delay} minutes"
|
23
|
+
mail.body = "Received - delay was #{delay} minutes - search by #{options}"
|
29
24
|
|
30
|
-
|
25
|
+
when :delayed
|
31
26
|
|
32
|
-
|
33
|
-
|
27
|
+
mail.subject = "Over #{delay} minutes delay"
|
28
|
+
mail.body = "Over #{delay} minutes delay - search by #{options}"
|
34
29
|
|
35
|
-
|
30
|
+
else
|
36
31
|
|
37
|
-
|
32
|
+
raise StandardError, "Incorrect type: #{type}"
|
38
33
|
|
39
34
|
end
|
40
35
|
|
41
36
|
mail
|
42
|
-
|
43
37
|
end
|
44
|
-
|
45
|
-
|
46
38
|
end
|
47
|
-
|
48
39
|
end
|
49
|
-
|
50
40
|
end
|
51
|
-
|
52
41
|
end
|
@@ -2,68 +2,49 @@ require_relative '../email'
|
|
2
2
|
require_relative '../../../errors'
|
3
3
|
|
4
4
|
module MailHandler
|
5
|
-
|
6
5
|
module Receiving
|
7
|
-
|
8
6
|
module Notification
|
9
|
-
|
10
7
|
class DelayState
|
11
|
-
|
12
8
|
attr_accessor :context,
|
13
9
|
:notified
|
14
10
|
|
15
11
|
def initialize(context)
|
16
|
-
|
17
12
|
@context = context
|
18
|
-
|
19
13
|
end
|
20
14
|
|
21
15
|
def notification_fired
|
22
|
-
|
23
16
|
@notified = true
|
24
|
-
|
25
17
|
end
|
26
18
|
|
27
|
-
def notify(
|
28
|
-
|
19
|
+
def notify(_search)
|
29
20
|
raise MailHandler::InterfaceError, 'notify(search) interface has to be implemented.'
|
30
|
-
|
31
21
|
end
|
32
22
|
|
33
23
|
protected
|
34
24
|
|
35
25
|
def send_notification_email(type, search)
|
36
|
-
|
37
26
|
unless notified
|
38
27
|
|
39
28
|
context.send_email(type, search)
|
40
29
|
notification_fired
|
41
30
|
|
42
31
|
end
|
43
|
-
|
44
32
|
end
|
45
|
-
|
46
33
|
end
|
47
34
|
|
48
35
|
class NoDelay < DelayState
|
49
|
-
|
50
36
|
def notify(search)
|
51
|
-
|
52
37
|
if Time.now - search.started_at >= context.min_time_to_notify
|
53
38
|
|
54
39
|
context.set_state(Delay.new(context))
|
55
40
|
context.notify(search)
|
56
41
|
|
57
42
|
end
|
58
|
-
|
59
43
|
end
|
60
|
-
|
61
44
|
end
|
62
45
|
|
63
46
|
class Delay < DelayState
|
64
|
-
|
65
47
|
def notify(search)
|
66
|
-
|
67
48
|
if search.result
|
68
49
|
|
69
50
|
context.set_state(Received.new(context))
|
@@ -79,36 +60,20 @@ module MailHandler
|
|
79
60
|
send_notification_email(:delayed, search)
|
80
61
|
|
81
62
|
end
|
82
|
-
|
83
63
|
end
|
84
|
-
|
85
64
|
end
|
86
65
|
|
87
66
|
class MaxDelay < DelayState
|
88
|
-
|
89
67
|
def notify(search)
|
90
|
-
|
91
68
|
send_notification_email(:delayed, search)
|
92
|
-
|
93
69
|
end
|
94
|
-
|
95
70
|
end
|
96
71
|
|
97
72
|
class Received < DelayState
|
98
|
-
|
99
73
|
def notify(search)
|
100
|
-
|
101
74
|
send_notification_email(:received, search)
|
102
|
-
|
103
75
|
end
|
104
|
-
|
105
76
|
end
|
106
|
-
|
107
77
|
end
|
108
|
-
|
109
78
|
end
|
110
|
-
|
111
79
|
end
|
112
|
-
|
113
|
-
|
114
|
-
|
@@ -1,37 +1,26 @@
|
|
1
1
|
module MailHandler
|
2
|
-
|
3
2
|
module Receiving
|
4
|
-
|
5
3
|
module Observer
|
6
|
-
|
7
4
|
def init_observer
|
5
|
+
@observers = []
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
def get_observers()
|
9
|
+
@observers
|
11
10
|
end
|
12
11
|
|
13
12
|
def add_observer(observer)
|
14
|
-
|
15
|
-
@observers ||= Array.new
|
13
|
+
@observers ||= []
|
16
14
|
@observers << observer
|
17
|
-
|
18
15
|
end
|
19
16
|
|
20
17
|
def delete_observer(observer)
|
21
|
-
|
22
18
|
@observers.delete(observer) if @observers
|
23
|
-
|
24
19
|
end
|
25
20
|
|
26
21
|
def notify_observers(search)
|
27
|
-
|
28
22
|
@observers.each { |observer| observer.notify(search) } if @observers
|
29
|
-
|
30
23
|
end
|
31
|
-
|
32
24
|
end
|
33
|
-
|
34
25
|
end
|
35
|
-
|
36
26
|
end
|
37
|
-
|
data/lib/mailhandler/sender.rb
CHANGED
@@ -4,9 +4,7 @@ require_relative 'sending/api_batch'
|
|
4
4
|
|
5
5
|
# Class for sending email, and storing details about the sending.
|
6
6
|
module MailHandler
|
7
|
-
|
8
7
|
class Sender
|
9
|
-
|
10
8
|
attr_accessor :dispatcher,
|
11
9
|
:sending
|
12
10
|
|
@@ -15,44 +13,34 @@ module MailHandler
|
|
15
13
|
# @param [int] - how long sending lasted, seconds
|
16
14
|
# @param [Object] - sending response message
|
17
15
|
# @param [Mail] - email/emails sent
|
18
|
-
Sending = Struct.new(
|
16
|
+
Sending = Struct.new(:started_at, :finished_at, :duration, :response, :email)
|
19
17
|
|
20
18
|
# @param [Sending::Oblect] dispatcher - sender type used for sending email
|
21
19
|
def initialize(dispatcher)
|
22
|
-
|
23
20
|
@dispatcher = dispatcher
|
24
21
|
@sending = Sending.new
|
25
|
-
|
26
22
|
end
|
27
23
|
|
28
24
|
def send_email(email)
|
29
|
-
|
30
25
|
init_sending_details(email)
|
31
26
|
response = dispatcher.send(email)
|
32
27
|
update_sending_details(response)
|
33
28
|
|
34
29
|
response
|
35
|
-
|
36
30
|
end
|
37
31
|
|
38
32
|
private
|
39
33
|
|
40
34
|
def init_sending_details(email)
|
41
|
-
|
42
35
|
@sending = Sending.new
|
43
36
|
@sending.started_at = Time.now
|
44
37
|
@sending.email = email
|
45
|
-
|
46
38
|
end
|
47
39
|
|
48
40
|
def update_sending_details(response)
|
49
|
-
|
50
41
|
@sending.finished_at = Time.now
|
51
42
|
@sending.duration = @sending.finished_at - @sending.started_at
|
52
43
|
@sending.response = response
|
53
|
-
|
54
44
|
end
|
55
|
-
|
56
45
|
end
|
57
|
-
|
58
|
-
end
|
46
|
+
end
|