mail_spy 0.0.2

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.
Files changed (83) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +68 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/mail_spy/application.js +15 -0
  5. data/app/assets/javascripts/mail_spy/tracking.js +2 -0
  6. data/app/assets/stylesheets/mail_spy/application.css +13 -0
  7. data/app/assets/stylesheets/mail_spy/tracking.css +4 -0
  8. data/app/controllers/mail_spy/application_controller.rb +4 -0
  9. data/app/controllers/mail_spy/tracking_controller.rb +53 -0
  10. data/app/helpers/mail_spy/application_helper.rb +4 -0
  11. data/app/helpers/mail_spy/email_helper.rb +40 -0
  12. data/app/mailers/mail_spy/core_mailer.rb +55 -0
  13. data/app/models/mail_spy/action.rb +23 -0
  14. data/app/models/mail_spy/campaign_report.rb +6 -0
  15. data/app/models/mail_spy/component_report.rb +6 -0
  16. data/app/models/mail_spy/email.rb +93 -0
  17. data/app/models/mail_spy/email_template.rb +17 -0
  18. data/app/models/mail_spy/stream_report.rb +6 -0
  19. data/app/views/layouts/mail_spy/application.html.erb +14 -0
  20. data/config/routes.rb +7 -0
  21. data/lib/generators/mail_spy/initialize_generator.rb +12 -0
  22. data/lib/generators/mail_spy/templates/mail_spy.rb +25 -0
  23. data/lib/mail_spy/engine.rb +13 -0
  24. data/lib/mail_spy/manager.rb +97 -0
  25. data/lib/mail_spy/version.rb +3 -0
  26. data/lib/mail_spy.rb +36 -0
  27. data/lib/tasks/mail_spy_tasks.rake +40 -0
  28. data/test/dummy/README.rdoc +261 -0
  29. data/test/dummy/Rakefile +7 -0
  30. data/test/dummy/app/assets/javascripts/application.js +15 -0
  31. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  32. data/test/dummy/app/controllers/application_controller.rb +3 -0
  33. data/test/dummy/app/helpers/application_helper.rb +2 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/test/dummy/config/application.rb +56 -0
  36. data/test/dummy/config/boot.rb +10 -0
  37. data/test/dummy/config/database.yml +25 -0
  38. data/test/dummy/config/environment.rb +5 -0
  39. data/test/dummy/config/environments/development.rb +37 -0
  40. data/test/dummy/config/environments/production.rb +67 -0
  41. data/test/dummy/config/environments/test.rb +37 -0
  42. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/test/dummy/config/initializers/inflections.rb +15 -0
  44. data/test/dummy/config/initializers/mime_types.rb +5 -0
  45. data/test/dummy/config/initializers/secret_token.rb +7 -0
  46. data/test/dummy/config/initializers/session_store.rb +8 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/locales/en.yml +5 -0
  49. data/test/dummy/config/mongoid.yml +20 -0
  50. data/test/dummy/config/routes.rb +4 -0
  51. data/test/dummy/config.ru +4 -0
  52. data/test/dummy/db/development.sqlite3 +0 -0
  53. data/test/dummy/db/seeds.rb +16 -0
  54. data/test/dummy/db/test.sqlite3 +0 -0
  55. data/test/dummy/log/development.log +212 -0
  56. data/test/dummy/log/test.log +6841 -0
  57. data/test/dummy/public/404.html +26 -0
  58. data/test/dummy/public/422.html +26 -0
  59. data/test/dummy/public/500.html +25 -0
  60. data/test/dummy/public/favicon.ico +0 -0
  61. data/test/dummy/script/rails +6 -0
  62. data/test/fixtures/mail_spy/actions.yml +7 -0
  63. data/test/fixtures/mail_spy/campaign_reports.yml +11 -0
  64. data/test/fixtures/mail_spy/component_reports.yml +11 -0
  65. data/test/fixtures/mail_spy/email_templates.yml +9 -0
  66. data/test/fixtures/mail_spy/emails.yml +15 -0
  67. data/test/fixtures/mail_spy/stream_reports.yml +11 -0
  68. data/test/functional/mail_spy/core_mailer_test.rb +33 -0
  69. data/test/functional/mail_spy/tracking_controller_test.rb +83 -0
  70. data/test/integration/navigation_test.rb +10 -0
  71. data/test/mail_spy_test.rb +7 -0
  72. data/test/test_email_credentials.yml +9 -0
  73. data/test/test_email_credentials.yml.sample +9 -0
  74. data/test/test_helper.rb +107 -0
  75. data/test/unit/helpers/mail_spy/tracking_helper_test.rb +6 -0
  76. data/test/unit/mail_spy/action_test.rb +9 -0
  77. data/test/unit/mail_spy/campaign_report_test.rb +9 -0
  78. data/test/unit/mail_spy/component_report_test.rb +9 -0
  79. data/test/unit/mail_spy/email_template_test.rb +9 -0
  80. data/test/unit/mail_spy/email_test.rb +9 -0
  81. data/test/unit/mail_spy/manager_test.rb +164 -0
  82. data/test/unit/mail_spy/stream_report_test.rb +9 -0
  83. metadata +343 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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,68 @@
1
+ = Mailspy
2
+
3
+ ESP agnostic sending and tracking platform for email campaigns
4
+
5
+ == Requirements
6
+
7
+ Mongodb > 1.8
8
+
9
+ == Setup
10
+
11
+ Add gem "mailspy" to your Gemfile
12
+ gem "mailspy"
13
+
14
+
15
+ Create the mongoid configuration for the mongo db
16
+
17
+ rails g mailspy:initialize
18
+
19
+ Fill out the generated mailspy_mongoid.yml with the mongodb configuration settings
20
+
21
+ Then mount the engine in the routes.rb file
22
+ Rails.application.routes.draw do
23
+ mount MailSpy::Engine => "/mailspy"
24
+ end
25
+
26
+ == Usage
27
+
28
+ To start using the viral tool simply enable it by
29
+
30
+ Adding the Virality module to Application Controller
31
+ class ApplicationController < ActionController::Base
32
+ include Virality
33
+ before_filter :track_virality
34
+
35
+ end
36
+
37
+ This will give you access to the following methods in lib/virality.rb these
38
+ methods are the complete client interface for the tool.
39
+
40
+ You will want to get started by instrumenting you code with the record_* methods
41
+ and using the message_for_conceit to populate your channel messages
42
+
43
+
44
+
45
+ == packaging into a application
46
+
47
+ If you don't have a private gem server you can package the gem into your
48
+ application since its not open source...
49
+
50
+ 1) gem build viral.gemspec
51
+ 2) rvm 1.9.2@global gem install viral-0.7.3.gem
52
+ 3) gem unpack viral -v '0.7.3' --target vendor/gems/
53
+ 4) Add the gemspec file to the vendored unpacked gem.
54
+ 5) bundle install
55
+
56
+ == Testing
57
+
58
+ You will need to add your own database.yml to the dummy app, rake db:create, and
59
+ rake db:migrate and rake db:test:prepare to get the dummy app setup.
60
+
61
+ Then you can simply run rake from the plugins test directory
62
+
63
+
64
+
65
+ == License
66
+ This project is property of Ooga Labs and not open source software
67
+
68
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'MailSpy'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ module MailSpy
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,53 @@
1
+ module MailSpy
2
+ class TrackingController < ApplicationController
3
+
4
+ def link
5
+ email_id = params[:eid]
6
+ head :unprocessable_entity and return if email_id.blank?
7
+
8
+ email = MailSpy::Email.find(email_id)
9
+ email.actions.create!(
10
+ :action_type => MailSpy::Action::ACTION_TYPE_CLICK,
11
+ :details => {
12
+ :url => params[:url],
13
+ :link_number => params[:n]
14
+ }
15
+ )
16
+
17
+ redirect_to params[:url]
18
+ end
19
+
20
+ def bug
21
+ email_id = params[:eid]
22
+ head :unprocessable_entity and return if email_id.blank?
23
+
24
+ #Mark the email as opened
25
+ email = MailSpy::Email.find(email_id)
26
+ email.actions.create!(
27
+ :action_type => MailSpy::Action::ACTION_TYPE_OPEN
28
+ )
29
+
30
+ head 200
31
+ end
32
+
33
+ def action
34
+ email_id = params[:eid]
35
+ action_type = params[:action_type]
36
+ details = params[:details]
37
+
38
+ head :unprocessable_entity and return if email_id.blank? || action_type.blank?
39
+ head :unprocessable_entity and return if details.present? && !details.kind_of?(Hash)
40
+
41
+ hash ={}
42
+ hash[:action_type] = action_type
43
+ hash[:count] = params[:count] if !params[:count].nil?
44
+ hash[:details] = details if details.present? && details.kind_of?(Hash)
45
+
46
+ # Save it up
47
+ email = MailSpy::Email.find(email_id)
48
+ email.actions.create!(hash)
49
+
50
+ head 200
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,4 @@
1
+ module MailSpy
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,40 @@
1
+ module MailSpy
2
+ module EmailHelper
3
+
4
+ # Support for link clicks.
5
+ def track_link(*args, &block)
6
+ @_track_count ||= 0
7
+ if block_given?
8
+ options = args.first || {}
9
+ html_options = args.second
10
+ track_link(capture(&block), options, html_options)
11
+ else
12
+ @_track_count += 1
13
+ name = args[0]
14
+ options = args[1] || {}
15
+ html_options = args[2]
16
+
17
+ html_options = convert_options_to_data_attributes(options, html_options)
18
+ url = url_for(options)
19
+
20
+ href = html_options['href']
21
+ tag_options = tag_options(html_options)
22
+
23
+ # Inject our tracking url, and pass in the redirect_url
24
+ url = url_for(:controller => "mail_spy/tracking", :action => :link, :url => url,
25
+ :n => @_track_count, :eid => @_email_id)
26
+
27
+
28
+ href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
29
+ "<a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a>".html_safe
30
+ end
31
+ end
32
+
33
+
34
+ # Support for open tracking, client support, etc
35
+ def tracking_bug
36
+ "<img src='#{url_for(:controller => "mail_spy/tracking", :action => :bug, :eid => @_email_id)}' />".html_safe
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,55 @@
1
+ module MailSpy
2
+ class CoreMailer < ActionMailer::Base
3
+ helper "mail_spy/email"
4
+
5
+ def template(email)
6
+ # Slight hack to provide information to helpers
7
+ @_email_id = email.id
8
+ @template_values = email.template_values
9
+
10
+ # Set Headers
11
+ email_hash = {}
12
+ std_email_keys = [:to, :cc, :bcc, :from, :subject, :message_id, :sender, :reply_to]
13
+ std_email_keys.each { |key| set_if_present(email_hash,email, key) }
14
+ headers.merge!(email.headers) if email.headers.present?
15
+
16
+ # Content of the email
17
+ html_erb = email.email_template.html_erb || ""
18
+ text_erb = email.email_template.html_erb || ""
19
+
20
+ mail_message = mail(email_hash) do |format|
21
+ format.text { render :inline => text_erb }
22
+ format.html { render :inline => html_erb }
23
+ end
24
+
25
+ # Email Service provider setup
26
+ # TODO Only support smtp at the moment
27
+ raise "No Email service providers installed" unless MailSpy.esps.present?
28
+ esp = MailSpy.esps[email.email_service_provider]
29
+ esp_key = MailSpy.esps.keys[rand(MailSpy.esps.keys.count)]
30
+ esp = MailSpy.esps[esp_key] if esp.blank?
31
+
32
+ mail_message.delivery_method.settings.merge!(
33
+ {
34
+ :address => esp.address,
35
+ :user_name => esp.user_name,
36
+ :password => esp.password,
37
+ :port => esp.port,
38
+ :authentication => esp.authentication,
39
+ :enable_starttls_auto => esp.enable_starttls_auto,
40
+ :domain => esp.domain
41
+ })
42
+
43
+ mail_message
44
+ end
45
+
46
+
47
+ protected
48
+
49
+ def set_if_present(email_hash, email, hash_key, email_key=nil)
50
+ email_key = hash_key if email_key.nil?
51
+ value = email.send("#{email_key}")
52
+ email_hash[hash_key] = value if value.present?
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ module MailSpy
2
+ class Action
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ ACTION_TYPE_OPEN = 'open'
7
+ ACTION_TYPE_CLICK = 'click'
8
+ ACTION_TYPE_BOUNCE = 'bounce'
9
+ ACTION_TYPE_UNSUBSCRIBE = 'unsubscribe'
10
+ ACTION_TYPE_SPAM = 'spam'
11
+
12
+ field :action_type, :type => String
13
+ field :count, :type => Integer, :default => 1
14
+ field :details, :type => Hash
15
+ embedded_in :email, :class_name => "MailSpy::Email"
16
+
17
+
18
+ def details
19
+ self.read_attribute(:details).try(:with_indifferent_access)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ module MailSpy
2
+ class CampaignReport
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module MailSpy
2
+ class ComponentReport
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ end
6
+ end
@@ -0,0 +1,93 @@
1
+ module MailSpy
2
+ class Email
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ # Standard Email options
7
+ field :to
8
+ field :cc
9
+ field :bcc
10
+ field :from
11
+ field :subject
12
+ field :sender #Sets envelope from (aka sender header)
13
+ field :reply_to
14
+ field :headers
15
+ field :message_id #Sets the unique id for each email
16
+
17
+ # Email content
18
+ field :template_name, :type => String
19
+ field :template_values, :type => Hash
20
+ belongs_to :email_template, :class_name => 'MailSpy::EmailTemplate'
21
+
22
+ # Support for tracking which esp ran the email
23
+ field :email_service_provider, :type => String
24
+
25
+ # References back to a user in another db
26
+ field :user_id, :type => Integer
27
+
28
+ # Structured campaign, stream and component settings
29
+ field :campaign, :type => String
30
+ field :stream, :type => String
31
+ field :component, :type => String
32
+
33
+ # Scheduling and completion
34
+ field :schedule_at, :type => DateTime
35
+ field :sent, :type => Boolean
36
+ index :schedule_at
37
+
38
+ # Record keeping of what happened
39
+ embeds_many :actions, :class_name => "MailSpy::Action"
40
+
41
+
42
+ def template_values
43
+ self.read_attribute(:template_values).try(:with_indifferent_access)
44
+ end
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
+ # Great for debugging emails
59
+ def parsed_html_content
60
+ return MailSpy::CoreMailer.template(self).text_part.body.to_s
61
+ end
62
+
63
+ def parsed_text_content
64
+ return MailSpy::CoreMailer.template(self).html_part.body.to_s
65
+ end
66
+
67
+
68
+ def self.generate_campaign_stats
69
+
70
+ map = <<-eof
71
+ function(){
72
+ emit(this.campaign, {count: 1});
73
+ }
74
+ eof
75
+
76
+ reduce = <<-eof
77
+ function(key, values){
78
+ var result = { count : 0 };
79
+
80
+ values.forEach(function(value){
81
+ result.count += value.count;
82
+ });
83
+ return result;
84
+ }
85
+ eof
86
+
87
+
88
+ results = collection.map_reduce(map, reduce, :out => "campaign_reports")
89
+ end
90
+
91
+ end
92
+ end
93
+
@@ -0,0 +1,17 @@
1
+ module MailSpy
2
+ class EmailTemplate
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ field :name, :type => String
6
+ field :html_erb, :type => String
7
+ field :text_erb, :type => String
8
+ field :template_values_definition, :type => Hash
9
+
10
+ index :name, :unique => true
11
+
12
+ has_many :emails, :class_name => 'MailSpy::Email'
13
+
14
+ validates_presence_of :name
15
+
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module MailSpy
2
+ class StreamReport
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>MailSpy</title>
5
+ <%= stylesheet_link_tag "mail_spy/application", :media => "all" %>
6
+ <%= javascript_include_tag "mail_spy/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ MailSpy::Engine.routes.draw do
2
+
3
+ match "t", :controller => :tracking, :action => :link
4
+ match "b", :controller => :tracking, :action => :bug
5
+ match "a", :controller => :tracking, :action => :action
6
+
7
+ end
@@ -0,0 +1,12 @@
1
+ module MailSpy
2
+ class InitializerGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("../templates", __FILE__)
4
+
5
+ desc "Generator creates a sample initializer"
6
+
7
+ def create_config_files
8
+ copy_file "mail_spy.rb", "config/initializers/mail_spy.rb"
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ # MailSpy allows you to add multiple email service providers simply
2
+ # call this method and specify the following options
3
+ #
4
+ # :name (must be unique for all esps you add)
5
+ # :via (stmp or sendmail)
6
+ #
7
+ # SMTP OPTIONS
8
+ # :address,
9
+ # :port,
10
+ # :authentication,
11
+ # :user_name,
12
+ # :password,
13
+ # :domain,
14
+ # :enable_starttls_auto
15
+
16
+ MailSpy.add_email_service_provider do |esp|
17
+ esp.name = "sendgrid"
18
+ esp.address = "smtp.sendgrid.net"
19
+ esp.port = "587",
20
+ esp.domain = "herokuapp.com"
21
+ esp.user_name = ENV['SENDGRID_USERNAME']
22
+ esp.password = ENV['SENDGRID_PASSWORD']
23
+ esp.authentication = :plain
24
+ esp.enable_starttls_auto = true
25
+ end
@@ -0,0 +1,13 @@
1
+ module MailSpy
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace MailSpy
4
+
5
+ # http://edgeapi.rubyonrails.org/classes/Rails/Engine.html
6
+ config.generators do |g|
7
+ g.orm :mongoid
8
+ g.template_engine :erb
9
+ g.test_framework :test_unit
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,97 @@
1
+ module MailSpy
2
+ module Manager
3
+
4
+ # ------------------------------------------- ADD_TEMPLATE
5
+ # Programmatically add email templates with a schema of search and
6
+ # replaceable text
7
+ #
8
+ def add_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
19
+ # Adds a instance of a email template to the queue to send
20
+ #
21
+ def add_instance(options)
22
+ options.to_options!
23
+
24
+ required_options = [
25
+ :template_name, :campaign, :stream, :component, :schedule_at, :subject,
26
+ :template_values, :from, :reply_to]
27
+ to_options = [:to, :cc, :bcc]
28
+
29
+ # Ensure that we have the required options
30
+ required_options.each { |ro| raise "add_instance call missing #{ro}" unless options.include? ro }
31
+
32
+ # Make sure we have someone to send to
33
+ has_sender = options.keys.select { |option| to_options.include? option.intern }.present?
34
+ raise "Email instance has no sender (to,cc,bcc were all blank)" unless has_sender
35
+
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 add_template first" unless template
40
+
41
+
42
+ # Make sure that
43
+ (required_options + to_options).each do |option|
44
+ unless MailSpy::Email.method_defined? "#{option}=".intern
45
+ raise "MailSpy::Email doesn't have #{option} as a setter '"
46
+ end
47
+ end
48
+
49
+
50
+ email = MailSpy::Email.create!(options)
51
+ email.email_template = template
52
+ email.save!
53
+ email
54
+ end
55
+
56
+ # ------------------------------------------- SEND OUTSTANDING EMAILS
57
+ # Batches through all the emails that were scheduled and have come due
58
+ # sends them out (step many at a time)
59
+ def send_outstanding_emails(step=100)
60
+ raise "No Email service providers installed" unless MailSpy.esps.present?
61
+
62
+ offset = 0
63
+ sent = 0
64
+
65
+ # Helper function for setting present values
66
+ def set_if_present(email, pony_hash, pony_key, email_key=nil)
67
+ email_key = pony_key if email_key.nil?
68
+ value = email.send("#{email_key}")
69
+ pony_hash[pony_key] = value if value.present?
70
+ end
71
+
72
+ while (true)
73
+ mails = MailSpy::Email.
74
+ limit(step).offset(offset).
75
+ where(:schedule_at.lte => DateTime.now, :sent => false).all
76
+ break if mails.blank?
77
+ mails.each do |email|
78
+ MailSpy::CoreMailer.template(email).deliver
79
+ email.update_attribute(:sent, true)
80
+ sent += 1
81
+ end
82
+ offset += step
83
+ end
84
+
85
+ sent
86
+ end
87
+
88
+
89
+ # ------------------------------------------- TRACKING
90
+ #
91
+
92
+ def track_other_action
93
+
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module MailSpy
2
+ VERSION = "0.0.2"
3
+ end