mail_room 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c956827ee8a391612edf608e8cfcca307fd40bf6
4
- data.tar.gz: 03d42253cf5fa4f3d9902cacb7ed3a1e45e414d3
3
+ metadata.gz: 9feac02c627c54d87da87bc73e1aec3587f43ff3
4
+ data.tar.gz: 55c2cd20c9e7b7036094c4d46c2efc93567f3e77
5
5
  SHA512:
6
- metadata.gz: c4316883fc6dee362bef9dfaefb7f88d70fe0641bdf35045b76c27d775b5bfa267cb858dc8593eb2d6488d0251a773e00e0636e7af86650a5bc65dabc07d3347
7
- data.tar.gz: 617090d049ac9c620909af604839c6ce9f71940ebcce43912d35875ac93fdad1b680137a4a702271d2b62ad19f9315d48b1ed16f6907b218278fae839f403d4b
6
+ metadata.gz: 29476b7c9e48f064087b59cc869ad6fab364044ca5a8fbf0f8fdb2dadb6a0222cdb07c473f4d82f0b75ccf895c063b56599bb1fd1acfa906309844f85bca3fb8
7
+ data.tar.gz: 030b4c91c26c545d2103d2d6f7147606bfafa7998c3b31251356b8da4241614260210863c9ef8ce04423ec91f95a381cf23fcdc648fc397368d2d33e5e6039f1
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
3
  - 2.0.0
5
4
  - 2.1.5
6
- - 2.2.0
5
+ - 2.2.4
6
+ - 2.3.0
7
7
  script: bundle exec rspec spec
8
8
  sudo: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## mail_room 0.7.0 ##
2
+
3
+ * Backports idle timeout from ruby 2.3.0
4
+ * Sets default to 29 minutes to prevent IMAP disconnects
5
+ * Validates that the timeout does not exceed 29 minutes
6
+
7
+ *Tony Pitale <@tpitale>*
8
+
1
9
  ## mail_room 0.6.1 ##
2
10
 
3
11
  * ERB parsing of configuration yml file to enable using ENV variables
data/CODE_OF_CONDUCT.md CHANGED
@@ -11,12 +11,14 @@ Examples of unacceptable behavior by participants include:
11
11
  * Trolling or insulting/derogatory comments
12
12
  * Public or private harassment
13
13
  * Publishing other's private information, such as physical or electronic addresses, without explicit permission
14
- * Other unethical or unprofessional conduct.
14
+ * Other unethical or unprofessional conduct
15
15
 
16
- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
16
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
17
+
18
+ By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
17
19
 
18
20
  This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
19
21
 
20
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
22
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [INSERT EMAIL ADDRESS]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
21
23
 
22
- This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
24
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at [http://contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/)
data/README.md CHANGED
@@ -7,7 +7,7 @@ mail_room is a configuration based process that will idle on IMAP connections an
7
7
  * Log the message or open with LetterOpener (Logger or LetterOpener)
8
8
 
9
9
  [![Build Status](https://travis-ci.org/tpitale/mail_room.png?branch=master)](https://travis-ci.org/tpitale/mail_room)
10
- [![Code Climate](https://codeclimate.com/github/tpitale/mail_room.png)](https://codeclimate.com/github/tpitale/mail_room)
10
+ [![Code Climate](https://codeclimate.com/github/tpitale/mail_room/badges/gpa.svg)](https://codeclimate.com/github/tpitale/mail_room)
11
11
 
12
12
  ## Installation ##
13
13
 
@@ -189,6 +189,11 @@ disabled, you can get the raw string of the email using `request.body.read`.
189
189
  I would recommend having the `mail` gem bundled and parse the email using
190
190
  `Mail.read_from_string(request.body.read)`.
191
191
 
192
+ ## idle_timeout ##
193
+
194
+ By default, the IDLE command will wait for 29 minutes (in order to keep the server connection happy).
195
+ If you'd prefer not to wait that long, you can pass `imap_timeout` in seconds for your mailbox configuration.
196
+
192
197
  ## Search Command ##
193
198
 
194
199
  This setting allows configuration of the IMAP search command sent to the server. This still defaults 'UNSEEN'. You may find that 'NEW' works better for you.
@@ -197,6 +202,8 @@ This setting allows configuration of the IMAP search command sent to the server.
197
202
 
198
203
  You can set per-mailbox configuration for the IMAP server's `host` (default: 'imap.gmail.com'), `port` (default: 993), `ssl` (default: true), and `start_tls` (default: false).
199
204
 
205
+ If you want to set additional options for IMAP SSL you can pass a YAML hash to match [SSLContext#set_params](http://docs.ruby-lang.org/en/2.2.0/OpenSSL/SSL/SSLContext.html#method-i-set_params). If you set `verify_mode` to `:none` it'll replace with the appropriate constant.
206
+
200
207
  If you're seeing the error `Please log in via your web browser: https://support.google.com/mail/accounts/answer/78754 (Failure)`, you need to configure your Gmail account to allow less secure apps to access it: https://support.google.com/accounts/answer/6010255.
201
208
 
202
209
  ## Running in Production ##
@@ -0,0 +1,33 @@
1
+ module MailRoom
2
+ class IMAP < Net::IMAP
3
+ # Backported 2.3.0 version of net/imap idle command to support timeout
4
+ def idle(timeout = nil, &response_handler)
5
+ raise LocalJumpError, "no block given" unless response_handler
6
+
7
+ response = nil
8
+
9
+ synchronize do
10
+ tag = Thread.current[:net_imap_tag] = generate_tag
11
+ put_string("#{tag} IDLE#{CRLF}")
12
+
13
+ begin
14
+ add_response_handler(response_handler)
15
+ @idle_done_cond = new_cond
16
+ @idle_done_cond.wait(timeout)
17
+ @idle_done_cond = nil
18
+ if @receiver_thread_terminating
19
+ raise Net::IMAP::Error, "connection closed"
20
+ end
21
+ ensure
22
+ unless @receiver_thread_terminating
23
+ remove_response_handler(response_handler)
24
+ put_string("DONE#{CRLF}")
25
+ response = get_tagged_response(tag, "IDLE")
26
+ end
27
+ end
28
+ end
29
+
30
+ return response
31
+ end
32
+ end
33
+ end
@@ -10,6 +10,7 @@ module MailRoom
10
10
  :port,
11
11
  :ssl,
12
12
  :start_tls,
13
+ :idle_timeout,
13
14
  :search_command,
14
15
  :name,
15
16
  :delete_after_delivery,
@@ -23,9 +24,17 @@ module MailRoom
23
24
  :arbitration_options
24
25
  ]
25
26
 
27
+ IdleTimeoutTooLarge = Class.new(RuntimeError)
28
+
26
29
  # Holds configuration for each of the email accounts we wish to monitor
27
30
  # and deliver email to when new emails arrive over imap
28
31
  Mailbox = Struct.new(*MAILBOX_FIELDS) do
32
+ # Keep it to 29 minutes or less
33
+ # The IMAP serve will close the connection after 30 minutes of inactivity
34
+ # (which sending IDLE and then nothing technically is), so we re-idle every
35
+ # 29 minutes, as suggested by the spec: https://tools.ietf.org/html/rfc2177
36
+ IMAP_IDLE_TIMEOUT = 29 * 60 # 29 minutes in in seconds
37
+
29
38
  # Default attributes for the mailbox configuration
30
39
  DEFAULTS = {
31
40
  :search_command => 'UNSEEN',
@@ -34,6 +43,7 @@ module MailRoom
34
43
  :port => 993,
35
44
  :ssl => true,
36
45
  :start_tls => false,
46
+ :idle_timeout => IMAP_IDLE_TIMEOUT,
37
47
  :delete_after_delivery => false,
38
48
  :delivery_options => {},
39
49
  :arbitration_method => 'noop',
@@ -44,6 +54,8 @@ module MailRoom
44
54
  # @param attributes [Hash] configuration options
45
55
  def initialize(attributes={})
46
56
  super(*DEFAULTS.merge(attributes).values_at(*members))
57
+
58
+ validate!
47
59
  end
48
60
 
49
61
  def delivery_klass
@@ -75,6 +87,17 @@ module MailRoom
75
87
  delivery.deliver(body)
76
88
  end
77
89
 
90
+ # true, false, or ssl options hash
91
+ def ssl_options
92
+ replace_verify_mode(ssl)
93
+ end
94
+
95
+ def validate!
96
+ if self[:idle_timeout] > IMAP_IDLE_TIMEOUT
97
+ raise IdleTimeoutTooLarge.new("Please use an idle timeout smaller than #{29*60} to prevent IMAP server disconnects")
98
+ end
99
+ end
100
+
78
101
  private
79
102
 
80
103
  def parsed_arbitration_options
@@ -84,5 +107,23 @@ module MailRoom
84
107
  def parsed_delivery_options
85
108
  delivery_klass::Options.new(self)
86
109
  end
110
+
111
+ def replace_verify_mode(options)
112
+ return options unless options.is_a?(Hash)
113
+ return options unless options.has_key?(:verify_mode)
114
+
115
+ options[:verify_mode] = case options[:verify_mode]
116
+ when :none, 'none'
117
+ OpenSSL::SSL::VERIFY_NONE
118
+ when :peer, 'peer'
119
+ OpenSSL::SSL::VERIFY_PEER
120
+ when :client_once, 'client_once'
121
+ OpenSSL::SSL::VERIFY_CLIENT_ONCE
122
+ when :fail_if_no_peer_cert, 'fail_if_no_peer_cert'
123
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
124
+ end
125
+
126
+ options
127
+ end
87
128
  end
88
129
  end
@@ -4,7 +4,7 @@ module MailRoom
4
4
  # Watch a Mailbox
5
5
  # @author Tony Pitale
6
6
  class MailboxWatcher
7
- attr_accessor :idling_thread, :timeout_thread
7
+ attr_accessor :idling_thread
8
8
 
9
9
  # Watch a new mailbox
10
10
  # @param mailbox [MailRoom::Mailbox] the mailbox to watch
@@ -17,7 +17,7 @@ module MailRoom
17
17
 
18
18
  # build a net/imap connection to google imap
19
19
  def imap
20
- @imap ||= Net::IMAP.new(@mailbox.host, :port => @mailbox.port, :ssl => @mailbox.ssl)
20
+ @imap ||= MailRoom::IMAP.new(@mailbox.host, :port => @mailbox.port, :ssl => @mailbox.ssl_options)
21
21
  end
22
22
 
23
23
  # build a handler to process mailbox messages
@@ -100,20 +100,8 @@ module MailRoom
100
100
 
101
101
  @idling = true
102
102
 
103
- self.timeout_thread = Thread.start do
104
- # The IMAP server will close the connection after 30 minutes of inactivity
105
- # (which sending IDLE and then nothing technically is), so we re-idle every
106
- # 29 minutes, as suggested by the spec: https://tools.ietf.org/html/rfc2177
107
- sleep 29 * 60
108
-
109
- imap.idle_done if idling?
110
- end
111
- timeout_thread.abort_on_exception = true
112
-
113
- imap.idle(&idle_handler)
103
+ imap.idle(@mailbox.idle_timeout, &idle_handler)
114
104
  ensure
115
- timeout_thread.kill if timeout_thread
116
- self.timeout_thread = nil
117
105
  @idling = false
118
106
  end
119
107
 
@@ -139,7 +127,7 @@ module MailRoom
139
127
  self.idling_thread = Thread.start do
140
128
  while(running?) do
141
129
  begin
142
- # block until we stop idling
130
+ # block for idle_timeout until we stop idling
143
131
  idle
144
132
 
145
133
  # when new messages are ready
@@ -1,4 +1,4 @@
1
1
  module MailRoom
2
2
  # Current version of MailRoom gem
3
- VERSION = "0.6.1"
3
+ VERSION = "0.7.0"
4
4
  end
data/lib/mail_room.rb CHANGED
@@ -6,6 +6,7 @@ module MailRoom
6
6
  end
7
7
 
8
8
  require "mail_room/version"
9
+ require "mail_room/backports/imap"
9
10
  require "mail_room/configuration"
10
11
  require "mail_room/mailbox"
11
12
  require "mail_room/mailbox_watcher"
@@ -89,5 +89,13 @@ describe MailRoom::Mailbox do
89
89
  noop.should have_received(:deliver).never
90
90
  end
91
91
  end
92
+
93
+ context "with ssl options hash" do
94
+ it 'replaces verify mode with constant' do
95
+ mailbox = MailRoom::Mailbox.new({:ssl => {:verify_mode => :none}})
96
+
97
+ expect(mailbox.ssl_options).to eq({:verify_mode => OpenSSL::SSL::VERIFY_NONE})
98
+ end
99
+ end
92
100
  end
93
101
  end
@@ -25,14 +25,12 @@ describe MailRoom::MailboxWatcher do
25
25
  end
26
26
 
27
27
  describe '#imap' do
28
- let(:mailbox) {MailRoom::Mailbox.new}
29
-
30
28
  it 'builds a new Net::IMAP object' do
31
- Net::IMAP.stubs(:new).returns('imap')
29
+ MailRoom::IMAP.stubs(:new).returns('imap')
32
30
 
33
31
  MailRoom::MailboxWatcher.new(mailbox).imap.should eq('imap')
34
32
 
35
- Net::IMAP.should have_received(:new).with('imap.gmail.com', :port => 993, :ssl => true)
33
+ MailRoom::IMAP.should have_received(:new).with('imap.gmail.com', :port => 993, :ssl => true)
36
34
  end
37
35
  end
38
36
 
@@ -40,7 +38,7 @@ describe MailRoom::MailboxWatcher do
40
38
  let(:imap) {stub(:login => true, :select => true)}
41
39
 
42
40
  let(:mailbox) {
43
- MailRoom::Mailbox.new(:email => 'user1@gmail.com', :password => 'password', :name => 'inbox', )
41
+ MailRoom::Mailbox.new(:email => 'user1@gmail.com', :password => 'password', :name => 'inbox')
44
42
  }
45
43
 
46
44
  let(:watcher) {
@@ -74,7 +72,7 @@ describe MailRoom::MailboxWatcher do
74
72
 
75
73
  describe '#idle' do
76
74
  let(:imap) {stub}
77
- let(:watcher) {MailRoom::MailboxWatcher.new(nil)}
75
+ let(:watcher) {MailRoom::MailboxWatcher.new(mailbox)}
78
76
 
79
77
  before :each do
80
78
  watcher.stubs(:imap).returns(imap)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Pitale
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-12 00:00:00.000000000 Z
11
+ date: 2016-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -200,6 +200,7 @@ files:
200
200
  - lib/mail_room/arbitration.rb
201
201
  - lib/mail_room/arbitration/noop.rb
202
202
  - lib/mail_room/arbitration/redis.rb
203
+ - lib/mail_room/backports/imap.rb
203
204
  - lib/mail_room/cli.rb
204
205
  - lib/mail_room/configuration.rb
205
206
  - lib/mail_room/coordinator.rb