mail_spy 0.0.4 → 0.0.5
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/README.rdoc +2 -7
- data/app/helpers/mail_spy/email_helper.rb +17 -3
- data/app/mailers/mail_spy/core_mailer.rb +11 -8
- data/app/models/mail_spy/email.rb +33 -14
- data/lib/generators/mail_spy/templates/mail_spy.rb +17 -1
- data/lib/mail_spy/manager.rb +9 -24
- data/lib/mail_spy/version.rb +1 -1
- data/lib/mail_spy.rb +29 -4
- data/test/dummy/app/views/email_templates/helper_test.html.erb +15 -0
- data/test/dummy/app/views/email_templates/helper_test.text.erb +11 -0
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/production.rb +5 -1
- data/test/dummy/config/environments/test.rb +4 -1
- data/test/dummy/config/initializers/mail_spy.rb +38 -0
- data/test/dummy/config/routes.rb +0 -1
- data/test/dummy/lib/tasks/emails.rake +8 -0
- data/test/dummy/log/development.log +12 -0
- data/test/dummy/log/test.log +3545 -0
- data/test/functional/mail_spy/core_mailer_test.rb +16 -9
- data/test/functional/mail_spy/tracking_controller_test.rb +1 -9
- data/test/test_email_credentials.yml +2 -2
- data/test/test_email_credentials.yml.sample +0 -8
- data/test/test_helper.rb +15 -41
- data/test/unit/mail_spy/manager_test.rb +91 -125
- metadata +37 -23
- data/app/models/mail_spy/email_template.rb +0 -17
- data/test/fixtures/mail_spy/email_templates.yml +0 -9
- data/test/unit/mail_spy/email_template_test.rb +0 -9
data/README.rdoc
CHANGED
@@ -20,6 +20,7 @@ Create the mongoid configuration for the mongo db
|
|
20
20
|
rails g mail_spy:initializer
|
21
21
|
|
22
22
|
Fill out the generated mailspy.rb with your esp settings (file has example)
|
23
|
+
and AWS settings
|
23
24
|
|
24
25
|
Then mount the engine in the routes.rb file
|
25
26
|
Rails.application.routes.draw do
|
@@ -32,13 +33,7 @@ Mailspy is centered around email templates and instances of those templates
|
|
32
33
|
(aka emails).
|
33
34
|
|
34
35
|
To create a template:
|
35
|
-
|
36
|
-
MailSpy.create_template(template_name, html_erb, text_erb, template_values_definition)
|
37
|
-
|
38
|
-
* Template name must be unique to all templates
|
39
|
-
* html, and text are the contents for a multipart email
|
40
|
-
* template_values_definition is a array of keys that should be present in the
|
41
|
-
template values of each hash
|
36
|
+
add a template to your s3 directory, campaign/stream/component.(text|html).erb
|
42
37
|
|
43
38
|
|
44
39
|
To create a instance:
|
@@ -21,8 +21,15 @@ module MailSpy
|
|
21
21
|
tag_options = tag_options(html_options)
|
22
22
|
|
23
23
|
# Inject our tracking url, and pass in the redirect_url
|
24
|
-
url = url_for(
|
25
|
-
|
24
|
+
url = url_for(
|
25
|
+
:controller => "mail_spy/tracking",
|
26
|
+
:action => :link,
|
27
|
+
:url => url,
|
28
|
+
:only_path => false,
|
29
|
+
:host => MailSpy.tracker_host,
|
30
|
+
:n => @_track_count,
|
31
|
+
:eid => @_email_id
|
32
|
+
)
|
26
33
|
|
27
34
|
|
28
35
|
href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
|
@@ -33,7 +40,14 @@ module MailSpy
|
|
33
40
|
|
34
41
|
# Support for open tracking, client support, etc
|
35
42
|
def tracking_bug
|
36
|
-
|
43
|
+
url = url_for(
|
44
|
+
:controller => "mail_spy/tracking",
|
45
|
+
:action => :bug,
|
46
|
+
:eid => @_email_id,
|
47
|
+
:only_path => false,
|
48
|
+
:host => MailSpy.tracker_host
|
49
|
+
)
|
50
|
+
"<img src='#{url}' style='display:none' width='1' height='1' border='0' />".html_safe
|
37
51
|
end
|
38
52
|
|
39
53
|
end
|
@@ -6,20 +6,23 @@ module MailSpy
|
|
6
6
|
# Slight hack to provide information to helpers
|
7
7
|
@_email_id = email.id
|
8
8
|
@template_values = email.template_values
|
9
|
+
email_hash = {}
|
10
|
+
|
11
|
+
|
12
|
+
# Evaluate the subject line as erb
|
13
|
+
if email.subject.present?
|
14
|
+
subject = ERB.new(email.subject).result(binding)
|
15
|
+
email_hash[:subject] = subject
|
16
|
+
end
|
9
17
|
|
10
18
|
# Set Headers
|
11
|
-
|
12
|
-
std_email_keys = [:to, :cc, :bcc, :from, :subject, :message_id, :sender, :reply_to]
|
19
|
+
std_email_keys = [:to, :cc, :bcc, :from, :message_id, :sender, :reply_to]
|
13
20
|
std_email_keys.each { |key| set_if_present(email_hash,email, key) }
|
14
21
|
headers.merge!(email.headers) if email.headers.present?
|
15
22
|
|
16
|
-
# Content of the email
|
17
|
-
html_erb = email.email_template.html_erb || ""
|
18
|
-
text_erb = email.email_template.html_erb || ""
|
19
|
-
|
20
23
|
mail_message = mail(email_hash) do |format|
|
21
|
-
format.text { render :inline => text_erb }
|
22
|
-
format.html { render :inline => html_erb }
|
24
|
+
format.text { render :inline => email.text_erb }
|
25
|
+
format.html { render :inline => email.html_erb }
|
23
26
|
end
|
24
27
|
|
25
28
|
# Email Service provider setup
|
@@ -3,6 +3,8 @@ module MailSpy
|
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Timestamps
|
5
5
|
|
6
|
+
@@template_cache = {}
|
7
|
+
|
6
8
|
# Standard Email options
|
7
9
|
field :to
|
8
10
|
field :cc
|
@@ -15,9 +17,7 @@ module MailSpy
|
|
15
17
|
field :message_id #Sets the unique id for each email
|
16
18
|
|
17
19
|
# Email content
|
18
|
-
field :template_name, :type => String
|
19
20
|
field :template_values, :type => Hash
|
20
|
-
belongs_to :email_template, :class_name => 'MailSpy::EmailTemplate'
|
21
21
|
|
22
22
|
# Support for tracking which esp ran the email
|
23
23
|
field :email_service_provider, :type => String
|
@@ -43,18 +43,6 @@ module MailSpy
|
|
43
43
|
self.read_attribute(:template_values).try(:with_indifferent_access)
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
def email_parts
|
48
|
-
template = self.email_template
|
49
|
-
html_erb = template.html_erb
|
50
|
-
text_erb = template.text_erb
|
51
|
-
mail = MailSpy::DummyMailer.template(html_erb, text_erb, self.template_values)
|
52
|
-
return {
|
53
|
-
:html => mail.html_part.body.to_s,
|
54
|
-
:text => mail.text_part.body.to_s
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
46
|
# Great for debugging emails
|
59
47
|
def parsed_html_content
|
60
48
|
return MailSpy::CoreMailer.template(self).text_part.body.to_s
|
@@ -64,6 +52,37 @@ module MailSpy
|
|
64
52
|
return MailSpy::CoreMailer.template(self).html_part.body.to_s
|
65
53
|
end
|
66
54
|
|
55
|
+
def html_erb
|
56
|
+
load_template("html.erb")
|
57
|
+
end
|
58
|
+
|
59
|
+
def text_erb
|
60
|
+
load_template("text.erb")
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Loads a template file from s3 using
|
66
|
+
def load_template(suffix)
|
67
|
+
raise "No aws_campaign_bucket_set" if MailSpy.aws_campaign_bucket.strip.blank?
|
68
|
+
|
69
|
+
# Check the cache using our convention
|
70
|
+
path = "#{self.campaign}/#{self.stream}/#{self.component}.#{suffix}"
|
71
|
+
return @@template_cache[path] if @@template_cache[path].present?
|
72
|
+
|
73
|
+
# Load the object from s3
|
74
|
+
s3 = AWS::S3.new(:access_key_id => MailSpy.aws_access_key_id,
|
75
|
+
:secret_access_key => MailSpy.aws_secret_access_key)
|
76
|
+
campaign_bucket = s3.buckets[MailSpy.aws_campaign_bucket]
|
77
|
+
campaign_bucket = buckets.create(MailSpy.aws_campaign_bucket) unless campaign_bucket.exists?
|
78
|
+
object = campaign_bucket.objects[path]
|
79
|
+
raise "no object found at path: #{path}" unless object.exists?
|
80
|
+
|
81
|
+
# Read and return
|
82
|
+
@@template_cache[path] = (object.read || "")
|
83
|
+
return @@template_cache[path]
|
84
|
+
end
|
85
|
+
|
67
86
|
|
68
87
|
def self.generate_campaign_stats
|
69
88
|
|
@@ -1,3 +1,19 @@
|
|
1
|
+
# MailSpy configuration
|
2
|
+
# tracking_host: The hostname and port (if necessary) of the server MailSpy
|
3
|
+
# will make requests to for tracking.
|
4
|
+
#
|
5
|
+
# aws credentials: We use aws to store the templates for the emails.
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
MailSpy.configure do |config|
|
10
|
+
config.tracker_host = "myapp.herokuapp.com"
|
11
|
+
config.aws_access_key_id = "YOUR ACCESS KEY"
|
12
|
+
config.aws_secret_access_key = "YOUR SECRET ACCESS KEY"
|
13
|
+
config.aws_campaign_bucket = "campaigns-yourco-com"
|
14
|
+
end
|
15
|
+
|
16
|
+
|
1
17
|
# MailSpy allows you to add multiple email service providers simply
|
2
18
|
# call this method and specify the following options
|
3
19
|
#
|
@@ -16,7 +32,7 @@
|
|
16
32
|
MailSpy.add_email_service_provider do |esp|
|
17
33
|
esp.name = "sendgrid"
|
18
34
|
esp.address = "smtp.sendgrid.net"
|
19
|
-
esp.port = "587"
|
35
|
+
esp.port = "587"
|
20
36
|
esp.domain = "herokuapp.com"
|
21
37
|
esp.user_name = ENV['SENDGRID_USERNAME']
|
22
38
|
esp.password = ENV['SENDGRID_PASSWORD']
|
data/lib/mail_spy/manager.rb
CHANGED
@@ -1,43 +1,28 @@
|
|
1
1
|
module MailSpy
|
2
2
|
module Manager
|
3
3
|
|
4
|
-
# -------------------------------------------
|
5
|
-
# Programmatically add email templates with a schema of search and
|
6
|
-
# replaceable text
|
7
|
-
#
|
8
|
-
def create_template(name, html_erb, text_erb, template_values_definition)
|
9
|
-
MailSpy::EmailTemplate.create!(
|
10
|
-
{
|
11
|
-
:name => name,
|
12
|
-
:html_erb => html_erb,
|
13
|
-
:text_erb => text_erb,
|
14
|
-
:template_values_definition => template_values_definition
|
15
|
-
})
|
16
|
-
end
|
17
|
-
|
18
|
-
# ------------------------------------------- ADD INSTANCE
|
4
|
+
# ------------------------------------------- CREATE EMAIL
|
19
5
|
# Adds a instance of a email template to the queue to send
|
20
6
|
#
|
21
7
|
def create_email(options)
|
22
8
|
options.to_options!
|
23
9
|
|
24
10
|
required_options = [
|
25
|
-
:
|
11
|
+
:campaign, :stream, :component, :schedule_at, :subject,
|
26
12
|
:template_values, :from, :reply_to]
|
27
13
|
to_options = [:to, :cc, :bcc]
|
28
14
|
|
29
15
|
# Ensure that we have the required options
|
30
16
|
required_options.each { |ro| raise "create_email call missing #{ro}" unless options.include? ro }
|
31
17
|
|
18
|
+
# Ensure that the campaign, stream and component are not blank
|
19
|
+
# These keys are used to define the s3 paths for the templates
|
20
|
+
[:campaign, :stream, :component].each { |key| raise "##{key} can't be blank" if options[key].blank? }
|
21
|
+
|
32
22
|
# Make sure we have someone to send to
|
33
23
|
has_sender = options.keys.select { |option| to_options.include? option.intern }.present?
|
34
24
|
raise "Email instance has no sender (to,cc,bcc were all blank)" unless has_sender
|
35
25
|
|
36
|
-
# Make sure we have a template
|
37
|
-
options[:template_name]
|
38
|
-
template = MailSpy::EmailTemplate.first(conditions: {name: options[:template_name]})
|
39
|
-
raise "No template: #{options[:template_name]} found, try create_template first" unless template
|
40
|
-
|
41
26
|
|
42
27
|
# Make sure that
|
43
28
|
(required_options + to_options).each do |option|
|
@@ -46,9 +31,7 @@ module MailSpy
|
|
46
31
|
end
|
47
32
|
end
|
48
33
|
|
49
|
-
|
50
34
|
email = MailSpy::Email.create!(options)
|
51
|
-
email.email_template = template
|
52
35
|
email.save!
|
53
36
|
email
|
54
37
|
end
|
@@ -75,7 +58,9 @@ module MailSpy
|
|
75
58
|
where(:schedule_at.lte => DateTime.now, :sent => false).all
|
76
59
|
break if mails.blank?
|
77
60
|
mails.each do |email|
|
78
|
-
MailSpy::CoreMailer.template(email)
|
61
|
+
mail = MailSpy::CoreMailer.template(email)
|
62
|
+
#TODO might be nice to flush mail out in debug mode
|
63
|
+
mail.deliver
|
79
64
|
email.update_attribute(:sent, true)
|
80
65
|
sent += 1
|
81
66
|
end
|
data/lib/mail_spy/version.rb
CHANGED
data/lib/mail_spy.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'pp' #For debugging
|
2
|
+
require 'aws-sdk'
|
2
3
|
require "mongoid"
|
3
4
|
require "mail_spy/engine"
|
4
5
|
require "mail_spy/manager"
|
@@ -14,12 +15,17 @@ module MailSpy
|
|
14
15
|
)
|
15
16
|
@@esps = {}
|
16
17
|
|
17
|
-
|
18
|
+
MailSpyConfig = Struct.new(
|
19
|
+
:tracker_host, :aws_access_key_id,
|
20
|
+
:aws_secret_access_key, :aws_campaign_bucket
|
21
|
+
|
22
|
+
)
|
23
|
+
@@config = MailSpyConfig.new
|
18
24
|
|
19
25
|
# Allows the initializer to set the configuration
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
def self.configure(&block)
|
27
|
+
block.call(@@config)
|
28
|
+
end
|
23
29
|
|
24
30
|
#TODO eventually have this be a view with a interface
|
25
31
|
def self.add_email_service_provider(&block)
|
@@ -32,5 +38,24 @@ module MailSpy
|
|
32
38
|
@@esps
|
33
39
|
end
|
34
40
|
|
41
|
+
def self.tracker_host
|
42
|
+
@@config.tracker_host
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.template_directory
|
46
|
+
@@config.template_directory
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.aws_access_key_id
|
50
|
+
@@config.aws_access_key_id
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.aws_secret_access_key
|
54
|
+
@@config.aws_secret_access_key
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.aws_campaign_bucket
|
58
|
+
@@config.aws_campaign_bucket
|
59
|
+
end
|
35
60
|
|
36
61
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<p>
|
2
|
+
You should be able to click on the link and have the server record the even
|
3
|
+
and forward you to the correct place.
|
4
|
+
|
5
|
+
A link : <%= track_link 'My home', 'www.google.com' %>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<br>
|
9
|
+
|
10
|
+
<p>
|
11
|
+
You should be able to show images in the email client and have the server
|
12
|
+
track the open
|
13
|
+
A Bug is in the parenthesis (<%= tracking_bug %>)
|
14
|
+
</p>
|
15
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
You should be able to click on the link and have the server record the even
|
2
|
+
and forward you to the correct place.
|
3
|
+
|
4
|
+
A link : <%= track_link 'My home', 'www.google.com' %>
|
5
|
+
---------------------------
|
6
|
+
|
7
|
+
You should be able to show images in the email client and have the server
|
8
|
+
track the open
|
9
|
+
A Bug is in the parenthesis (<%= tracking_bug %>)
|
10
|
+
|
11
|
+
|
@@ -14,7 +14,7 @@ Dummy::Application.configure do
|
|
14
14
|
config.action_controller.perform_caching = false
|
15
15
|
|
16
16
|
# Don't care if the mailer can't send
|
17
|
-
config.action_mailer.raise_delivery_errors =
|
17
|
+
config.action_mailer.raise_delivery_errors = true
|
18
18
|
|
19
19
|
# Print deprecation notices to the Rails logger
|
20
20
|
config.active_support.deprecation = :log
|
@@ -5,7 +5,7 @@ Dummy::Application.configure do
|
|
5
5
|
config.cache_classes = true
|
6
6
|
|
7
7
|
# Full error reports are disabled and caching is turned on
|
8
|
-
config.consider_all_requests_local
|
8
|
+
config.consider_all_requests_local = false
|
9
9
|
config.action_controller.perform_caching = true
|
10
10
|
|
11
11
|
# Disable Rails's static asset server (Apache or nginx will already do this)
|
@@ -64,4 +64,8 @@ Dummy::Application.configure do
|
|
64
64
|
# Log the query plan for queries taking more than this (works
|
65
65
|
# with SQLite, MySQL, and PostgreSQL)
|
66
66
|
# config.active_record.auto_explain_threshold_in_seconds = 0.5
|
67
|
+
|
68
|
+
# Raise errors on mailer failure
|
69
|
+
config.action_mailer.raise_delivery_errors = true
|
70
|
+
|
67
71
|
end
|
@@ -27,11 +27,14 @@ Dummy::Application.configure do
|
|
27
27
|
# Tell Action Mailer not to deliver emails to the real world.
|
28
28
|
# The :test delivery method accumulates sent emails in the
|
29
29
|
# ActionMailer::Base.deliveries array.
|
30
|
-
config.action_mailer.delivery_method = :
|
30
|
+
config.action_mailer.delivery_method = :smtp
|
31
31
|
|
32
32
|
# Raise exception on mass assignment protection for Active Record models
|
33
33
|
config.active_record.mass_assignment_sanitizer = :strict
|
34
34
|
|
35
35
|
# Print deprecation notices to the stderr
|
36
36
|
config.active_support.deprecation = :stderr
|
37
|
+
|
38
|
+
# Raise errors on mailer failure
|
39
|
+
config.action_mailer.raise_delivery_errors = true
|
37
40
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# MailSpy configuration
|
2
|
+
# tracking_host: The hostname and port (if necessary) of the server MailSpy
|
3
|
+
# will make requests to for tracking.
|
4
|
+
|
5
|
+
|
6
|
+
MailSpy.configure do |config|
|
7
|
+
config.tracker_host = "localhost:5000"
|
8
|
+
config.aws_access_key_id = "AKIAIF6DRMAH3BR47AZQ"
|
9
|
+
config.aws_secret_access_key = "iy3wBOLSX0a7clbfYPSqvDprVnUzQURokZUazMpZ"
|
10
|
+
config.aws_campaign_bucket = "daviacalendar-mailspy"
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# MailSpy allows you to add multiple email service providers simply
|
15
|
+
# call this method and specify the following options
|
16
|
+
#
|
17
|
+
# :name (must be unique for all esps you add)
|
18
|
+
# :via (stmp or sendmail)
|
19
|
+
#
|
20
|
+
# SMTP OPTIONS
|
21
|
+
# :address,
|
22
|
+
# :port,
|
23
|
+
# :authentication,
|
24
|
+
# :user_name,
|
25
|
+
# :password,
|
26
|
+
# :domain,
|
27
|
+
# :enable_starttls_auto
|
28
|
+
|
29
|
+
MailSpy.add_email_service_provider do |esp|
|
30
|
+
esp.name = "sendgrid"
|
31
|
+
esp.address = "smtp.sendgrid.net"
|
32
|
+
esp.port = "587"
|
33
|
+
esp.domain = "herokuapp.com"
|
34
|
+
esp.user_name = "app2602840@heroku.com"
|
35
|
+
esp.password = "qb6qnim0"
|
36
|
+
esp.authentication = :plain
|
37
|
+
esp.enable_starttls_auto = true
|
38
|
+
end
|
data/test/dummy/config/routes.rb
CHANGED
@@ -210,3 +210,15 @@ MONGODB dummy_development['mail_spy_emails'].find({}).limit(-1).sort([[:_id, :de
|
|
210
210
|
MONGODB dummy_development['mail_spy_emails'].find({}).limit(-1).sort([[:_id, :desc]])
|
211
211
|
MONGODB dummy_development['system.namespaces'].find({})
|
212
212
|
MONGODB dummy_development['mail_spy_emails'].find({}).limit(-1).sort([[:_id, :desc]])
|
213
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
214
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|
215
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
216
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|
217
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
218
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|
219
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
220
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|
221
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
222
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|
223
|
+
MONGODB [WARNING] Please note that logging negatively impacts client-side performance. You should set your logging level no lower than :info in production.
|
224
|
+
MONGODB admin['$cmd'].find({:ismaster=>1}).limit(-1)
|