canonical-email 1.0.0

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Centro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,108 @@
1
+ = Canonical
2
+
3
+ Canonical is an ActionMailer extension that acts just like the Postfix
4
+ utility of the same name. Essentially, Canonical lets you substitute the To,
5
+ CC, and/or BCC email destinations with one of many replacements via a rule.
6
+
7
+ You may want this behavior for many reasons; especially if you're actually
8
+ using Postfix's canonical functionality. Let's say you don't want to setup
9
+ your integration or staging environment to send email in test mode, but you
10
+ also do not want to accidentally send email to real users. You may add a
11
+ canonical rule like the following to send any email from the system to any
12
+ address to the QA email distribution list:
13
+
14
+ TMail::Mail.add_canonical_override(/.*/, 'qa@foo.bar')
15
+
16
+ Assuming you are working at Foo Bar, that rule will match any destination
17
+ address that has any character in it - meaning, it matches everything - and
18
+ will subsitute the matched email with qa@foo.bar. This is the same as saying
19
+ the following in Postfix's canonical file:
20
+
21
+ /.*/, qa@foo.bar
22
+
23
+ What you should notice is that canonical expects to see a regular expression
24
+ as the first argument. Passing in anything that does not respond to =~ will
25
+ result in an error.
26
+
27
+ == First matched, first replaced (FMFR)
28
+
29
+ Now, let's say you didn't want to just replace everything. Let's you wanted
30
+ to send everything for your boss to your team, everything to marketing to
31
+ another email address, and catch everything else. The rules would then be
32
+ defined as:
33
+
34
+ TMail::Mail.add_canonical_override(/ceo@foo\.bar/, 'developers@foo.bar')
35
+ TMail::Mail.add_canonical_override(/marketing@/, 'technology@foo.bar')
36
+ TMail::Mail.add_canonical_override(/.*/, 'qa@foo.bar')
37
+
38
+ What you should notice here is the ordering. Canonical works with multiple
39
+ rules, but will process a substition according to the rule that matches first.
40
+ Thus, whichever rule you define first will be checked first. If the rule matches
41
+ the email address being checked, the substitution is made and matching stops.
42
+ Hence the FMFR; first matched, first replaced.
43
+
44
+ The best way to take advantage of rules is to put the most specific rule at the
45
+ top of the list and the most generic rule at the bottom. If we had reversed the
46
+ order of the above rules, everything would go to qa@foo.bar.
47
+
48
+ == Passing Through
49
+
50
+ Perhaps you have a catch-all rule like the ones used above (e.g. /.*/), but you
51
+ want certain email addresses to pass-through. Sort of like an opt-in approach,
52
+ which might be considered safer in a closed environment. You could match on the
53
+ specific address and then substitute it with the same thing, like so:
54
+
55
+ TMail::Mail.add_canonical_override(/ceo@foo\.bar/, 'ceo@foo.bar')
56
+
57
+ But that's kind of silly; and what if you wanted to match on everything for your
58
+ company? This is where Canonical deviates slightly from Postfix's version. This
59
+ Canonical will allow you to provide a passthrough for a pattern. For instance:
60
+
61
+ TMail::Mail.add_canonical_passthrough(/@foo\.bar/)
62
+
63
+ Will explicitly allow any email address with "@foo.bar" in it. Even if there is
64
+ a catch-all rule; so long as this rule comes before any other rules that would
65
+ match.
66
+
67
+ Handy? Yes!
68
+
69
+ == How does it work
70
+
71
+ Essentially, Canonical works by hijacking the TMail::Mail#destinations which is
72
+ used at the moment ActionMailer is about to write the RCPT TOs to the SMTP
73
+ server chosen. Canonical only modifies destinations, it does not modify anything
74
+ about the body of the email. Thus, the To, Cc, and Bcc will all look the same
75
+ as an unmodified email would to the recipient.
76
+
77
+ Canonical also disables the :sendmail option since it only tries to work with
78
+ SMTP. At some point in the future, this may change. If you need sendmail support
79
+ then fix the code and send a patch :)
80
+
81
+ == How should I use it?
82
+
83
+ The most obvious way to use canonical is to put the rules in your Rails
84
+ environment files. We suggest an opt-in approach to rule setting such that you
85
+ catch-all in config/environment.rb and specifically allow emails in
86
+ config/environments/production.rb.
87
+
88
+ For example:
89
+
90
+ # config/environment.rb
91
+ ...
92
+ TMail::Mail.add_canonical_override(/.*/, 'testing@foo.bar')
93
+
94
+ # config/environments/production.rb
95
+ ...
96
+ TMail::Mail.add_canonical_passthrough(/.*/)
97
+
98
+ That's the most basic way to localize email in every environment but production.
99
+
100
+ = License
101
+
102
+ Copyright (c) 2008 {Centro}[www.centro.net], released under the MIT license.
103
+
104
+ Authored by:
105
+
106
+ {Eric Schwartz}[eric.schwartz@centro.net]
107
+ {Brett Neumeier}[brett.neumeier@centro.net]
108
+ {Justin Knowlden}[justin.knowlden@centro.net]
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "canonical-email"
8
+ gem.summary = %Q{Safely and easily rewrite your email destination headers in Ruby}
9
+ gem.description = %Q{canonical-email lets you substitute the To, CC, and/or BCC email destinations with one of many replacements via a simple regular expression.}
10
+ gem.homepage = "http://github.com/centro/canonical-email"
11
+ gem.authors = ['emschwar', 'jaknowlden']
12
+ gem.add_development_dependency "actionmailer", ">=2.1.0"
13
+ gem.add_development_dependency "actionpack", ">=2.1.0"
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ desc 'Default: run unit tests.'
21
+ task :default => :test
22
+
23
+ desc 'Test the canonical plugin.'
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.pattern = 'test/**/*_test.rb'
27
+ t.verbose = true
28
+ end
29
+
30
+ require 'rake/rdoctask'
31
+ desc 'Generate documentation for the canonical plugin.'
32
+ Rake::RDocTask.new(:rdoc) do |rdoc|
33
+ rdoc.rdoc_dir = 'rdoc'
34
+ rdoc.title = 'Canonical'
35
+ rdoc.options << '--line-numbers' << '--inline-source'
36
+ rdoc.rdoc_files.include('README')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'action_mailer'
2
+ require 'canonical'
3
+ require 'disallow_sendmail_method'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,138 @@
1
+ require 'disallow_sendmail_method'
2
+
3
+ module Centro #:nodoc:
4
+ =begin rdoc
5
+ Canonical is an ActionMailer extension that acts just like the Postfix
6
+ utility of the same name. Essentially, Canonical lets you substitute the To,
7
+ CC, and/or BCC email destinations with one of many replacements via a rule.
8
+
9
+ You may want this behavior for many reasons; especially if you're actually
10
+ using Postfix's canonical functionality. Let's say you don't want to setup
11
+ your integration or staging environment to send email in test mode, but you
12
+ also do not want to accidentally send email to real users. You may add a
13
+ canonical rule like the following to send any email from the system to any
14
+ address to the QA email distribution list:
15
+
16
+ TMail::Mail.add_canonical_override(/.*/, 'qa@foo.bar')
17
+
18
+ Assuming you are working at Foo Bar, that rule will match any destination
19
+ address that has any character in it - meaning, it matches everything - and
20
+ will subsitute the matched email with qa@foo.bar. This is the same as saying
21
+ the following in Postfix's canonical file:
22
+
23
+ /.*/, qa@foo.bar
24
+
25
+ What you should notice is that canonical expects to see a regular expression
26
+ as the first argument. Passing in anything that does not respond to =~ will
27
+ result in an error.
28
+
29
+ = First matched, first replaced (FMFR)
30
+
31
+ Now, let's say you didn't want to just replace everything. Let's you wanted
32
+ to send everything for your boss to your team, everything to marketing to
33
+ another email address, and catch everything else. The rules would then be
34
+ defined as:
35
+
36
+ TMail::Mail.add_canonical_override(/ceo@foo\.bar/, 'developers@foo.bar')
37
+ TMail::Mail.add_canonical_override(/marketing@/, 'technology@foo.bar')
38
+ TMail::Mail.add_canonical_override(/.*/, 'qa@foo.bar')
39
+
40
+ What you should notice here is the ordering. Canonical works with multiple
41
+ rules, but will process a substition according to the rule that matches first.
42
+ Thus, whichever rule you define first will be checked first. If the rule matches
43
+ the email address being checked, the substitution is made and matching stops.
44
+ Hence the FMFR; first matched, first replaced.
45
+
46
+ The best way to take advantage of rules is to put the most specific rule at the
47
+ top of the list and the most generic rule at the bottom. If we had reversed the
48
+ order of the above rules, everything would go to qa@foo.bar.
49
+
50
+ = Passing Through
51
+
52
+ Perhaps you have a catch-all rule like the ones used above (e.g. /.*/), but you
53
+ want certain email addresses to pass-through. Sort of like an opt-in approach,
54
+ which might be considered safer in a closed environment. You could match on the
55
+ specific address and then substitute it with the same thing, like so:
56
+
57
+ TMail::Mail.add_canonical_override(/ceo@foo\.bar/, 'ceo@foo.bar')
58
+
59
+ But that's kind of silly; and what if you wanted to match on everything for your
60
+ company? This is where Canonical deviates slightly from Postfix's version. This
61
+ Canonical will allow you to provide a passthrough for a pattern. For instance:
62
+
63
+ TMail::Mail.add_canonical_passthrough(/@foo\.bar/)
64
+
65
+ Will explicitly allow any email address with "@foo.bar" in it. Even if there is
66
+ a catch-all rule; so long as this rule comes before any other rules that would
67
+ match.
68
+
69
+ Handy? Yes!
70
+
71
+ = How does it work
72
+
73
+ Essentially, Canonical works by hijacking the TMail::Mail#destinations which is
74
+ used at the moment ActionMailer is about to write the RCPT TOs to the SMTP
75
+ server chosen. Canonical only modifies destinations, it does not modify anything
76
+ about the body of the email. Thus, the To, Cc, and Bcc will all look the same
77
+ as an unmodified email would to the recipient.
78
+
79
+ Canonical also disables the :sendmail option since it only tries to work with
80
+ SMTP. At some point in the future, this may change. If you need sendmail support
81
+ then fix the code and send a patch :)
82
+ =end
83
+ module Canonical
84
+
85
+ def self.included(klass)
86
+ klass.extend(ClassMethods)
87
+ klass.send(:include, InstanceMethods)
88
+ end
89
+
90
+ module ClassMethods
91
+ def clear_canonical
92
+ self.overrides = nil
93
+ end
94
+
95
+ def add_canonical_passthrough(pattern)
96
+ overrides << [ pattern, :passthrough ]
97
+ end
98
+
99
+ def add_canonical_override(pattern, override)
100
+ overrides << [ pattern, override ]
101
+ end
102
+
103
+ def canonical_destination(email)
104
+ overrides.each do |pattern, replace|
105
+ return (:passthrough == replace ? email : replace) if email =~ pattern
106
+ end
107
+ email
108
+ end
109
+
110
+ private
111
+
112
+ def overrides
113
+ @@smtp_overridden ||= []
114
+ end
115
+
116
+ def overrides=(overrides)
117
+ @@smtp_overridden = overrides
118
+ end
119
+
120
+ end # ClassMethods
121
+
122
+ module InstanceMethods
123
+ def canonical_destinations
124
+ self.destinations_without_canonical.collect do |email|
125
+ self.class.canonical_destination(email)
126
+ end.uniq
127
+ end
128
+
129
+ def self.included(base)
130
+ base.send(:alias_method, :destinations_without_canonical, :destinations)
131
+ base.send(:alias_method, :destinations, :canonical_destinations)
132
+ end
133
+
134
+ end # InstanceMethods
135
+ end # Canonical
136
+ end # Centro
137
+
138
+ TMail::Mail.send(:include, Centro::Canonical)
@@ -0,0 +1,7 @@
1
+ class ActionMailer::Base
2
+ def perform_delivery_sendmail(ignored)
3
+ raise SecurityError,
4
+ "[Canonical] Sendmail method is explicitly disallowed so that we don't " +
5
+ "accidentally configure ourselves into a security hole"
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :canonical do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,61 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class CanonicalTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @mail = TMail::Mail.new
7
+ end
8
+
9
+ def teardown
10
+ TMail::Mail.clear_canonical
11
+ end
12
+
13
+ def test_add_override_rewrites_matching_destinations
14
+ TMail::Mail.add_canonical_override(/me\.please$/, "foo@bar.com")
15
+ assert_equal "foo@bar.com",
16
+ TMail::Mail.canonical_destination("override@me.please")
17
+ end
18
+
19
+ def test_add_override_ignores_non_matching_destinations
20
+ TMail::Mail.add_canonical_override(/me\.please$/, "foo@bar.com")
21
+ assert_equal "same@centro.net",
22
+ TMail::Mail.canonical_destination("same@centro.net")
23
+ end
24
+
25
+ def test_add_override_does_not_change_destination_with_passthrough
26
+ TMail::Mail.add_canonical_override(/@centro.net$/, :passthrough)
27
+ assert_equal "passthrough@centro.net",
28
+ TMail::Mail.canonical_destination("passthrough@centro.net")
29
+ end
30
+
31
+ def test_add_passthrough_does_not_change_destination
32
+ TMail::Mail.add_canonical_passthrough(/@centro.net$/)
33
+ assert_equal "passthrough@centro.net",
34
+ TMail::Mail.canonical_destination("passthrough@centro.net")
35
+ end
36
+
37
+ def test_overrides_are_applied_in_the_order_they_were_added
38
+ TMail::Mail.add_canonical_passthrough(/@centro.net$/)
39
+ TMail::Mail.add_canonical_override(/.*/, "redirect@centro.net")
40
+
41
+ assert_equal "same@centro.net",
42
+ TMail::Mail.canonical_destination("same@centro.net")
43
+ assert_equal "redirect@centro.net",
44
+ TMail::Mail.canonical_destination("some@random.addr.com")
45
+ end
46
+
47
+ def test_overrides_rewrite_tmail_destinations
48
+ TMail::Mail.add_canonical_override(/.*/, "redirect@centro.net")
49
+
50
+ @mail.to = "foo@bar.com"
51
+ assert_equal ["redirect@centro.net"], @mail.destinations
52
+ end
53
+
54
+ def test_overrides_should_list_unique_replacements
55
+ TMail::Mail.add_canonical_override(/.*/, "redirect@centro.net")
56
+
57
+ @mail.to = ["foo@bar.com", "bar@foo.com"]
58
+ assert_equal ["redirect@centro.net"], @mail.destinations
59
+ end
60
+
61
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class DisallowSendmailMethodTest < Test::Unit::TestCase
4
+
5
+ class MyMailer < ActionMailer::Base
6
+ def self.template_root
7
+ File.dirname(__FILE__)
8
+ end
9
+
10
+ def test_mail
11
+ part :content_type => 'text/plain', :body => "a test"
12
+ end
13
+ end
14
+
15
+ def test_sendmail_method_raises_security_error
16
+ ActionMailer::Base.delivery_method = :sendmail
17
+ ActionMailer::Base.template_root = "."
18
+ assert_raises (SecurityError) { MyMailer.deliver_test_mail }
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'action_mailer'
4
+ require 'action_controller'
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'canonical-email')
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: canonical-email
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - emschwar
13
+ - jaknowlden
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-03-29 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: actionmailer
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 1
31
+ - 0
32
+ version: 2.1.0
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: actionpack
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 2
44
+ - 1
45
+ - 0
46
+ version: 2.1.0
47
+ type: :development
48
+ version_requirements: *id002
49
+ description: canonical-email lets you substitute the To, CC, and/or BCC email destinations with one of many replacements via a simple regular expression.
50
+ email:
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - README.rdoc
57
+ files:
58
+ - MIT-LICENSE
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - init.rb
63
+ - install.rb
64
+ - lib/canonical-email.rb
65
+ - lib/disallow_sendmail_method.rb
66
+ - tasks/canonical.rake
67
+ - test/canonical_test.rb
68
+ - test/disallow_sendmail_method_test.rb
69
+ - test/test_helper.rb
70
+ - uninstall.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/centro/canonical-email
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options:
77
+ - --charset=UTF-8
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.6
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Safely and easily rewrite your email destination headers in Ruby
101
+ test_files:
102
+ - test/canonical_test.rb
103
+ - test/disallow_sendmail_method_test.rb
104
+ - test/test_helper.rb