mail_spy 0.0.16 → 0.0.17
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/app/models/mail_spy/email.rb +48 -0
- data/app/models/mail_spy/process_log.rb +25 -0
- data/lib/mail_spy/manager.rb +35 -9
- data/lib/mail_spy/version.rb +1 -1
- data/test/dummy/db/seeds.rb +16 -13
- data/test/dummy/log/development.log +724 -0
- data/test/dummy/log/test.log +2372 -0
- data/test/fixtures/mail_spy/process_logs.yml +15 -0
- data/test/functional/mail_spy/tracking_controller_test.rb +13 -1
- data/test/unit/mail_spy/manager_test.rb +25 -12
- data/test/unit/mail_spy/process_log_test.rb +9 -0
- metadata +7 -2
@@ -99,6 +99,54 @@ module MailSpy
|
|
99
99
|
end
|
100
100
|
|
101
101
|
|
102
|
+
|
103
|
+
#var key_hash = {
|
104
|
+
# campaign:this.campaign,
|
105
|
+
# stream:this.stream,
|
106
|
+
# component:this.component,
|
107
|
+
# campaign:this.subject
|
108
|
+
#};
|
109
|
+
#
|
110
|
+
|
111
|
+
|
112
|
+
def self.generate_subject_reports
|
113
|
+
map = <<-eof
|
114
|
+
function(){
|
115
|
+
var action_counts = {};
|
116
|
+
for(var i=0, len = this.actions.length; i < len; i++){
|
117
|
+
var action = this.actions[i];
|
118
|
+
action_counts[action.action_type] = action_counts[action.action_type] || 0;
|
119
|
+
action_counts[action.action_type]++;
|
120
|
+
}
|
121
|
+
|
122
|
+
emit({
|
123
|
+
campaign:this.campaign,
|
124
|
+
stream:this.stream,
|
125
|
+
component:this.component,
|
126
|
+
subject:this.subject
|
127
|
+
}, action_counts);
|
128
|
+
}
|
129
|
+
eof
|
130
|
+
|
131
|
+
reduce = <<-eof
|
132
|
+
function(key, values){
|
133
|
+
var result = {};
|
134
|
+
|
135
|
+
values.forEach(function(hash){
|
136
|
+
for(var key in hash){
|
137
|
+
result[key] = result[key] || 0
|
138
|
+
result[key] += hash[key]
|
139
|
+
}
|
140
|
+
});
|
141
|
+
|
142
|
+
return result;
|
143
|
+
}
|
144
|
+
eof
|
145
|
+
|
146
|
+
results = collection.map_reduce(map, reduce, :out => "test_reports")
|
147
|
+
|
148
|
+
end
|
149
|
+
|
102
150
|
def self.generate_campaign_stats
|
103
151
|
|
104
152
|
map = <<-eof
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MailSpy
|
2
|
+
class ProcessLog
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
|
6
|
+
field :start, :type => Time
|
7
|
+
field :end, :type => Time
|
8
|
+
field :seconds_elapsed, :type => Integer
|
9
|
+
field :success, :type => Boolean, :default => false
|
10
|
+
field :running, :type => Boolean, :default => false
|
11
|
+
|
12
|
+
|
13
|
+
def self.currently_processing?
|
14
|
+
self.where(:running => true).first.present?
|
15
|
+
end
|
16
|
+
|
17
|
+
# Deletes logs after a given date if no date is given we default
|
18
|
+
# to logs that are older that 3 months.
|
19
|
+
def self.delete_stale_logs(date=nil)
|
20
|
+
date = Time.now.advance(:months => -3) if date.nil?
|
21
|
+
self.where("created_at < #{date}").delete_all
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/mail_spy/manager.rb
CHANGED
@@ -19,11 +19,11 @@ module MailSpy
|
|
19
19
|
# These keys are used to define the s3 paths for the templates
|
20
20
|
[:campaign, :stream, :component].each { |key| raise "##{key} can't be blank" if options[key].blank? }
|
21
21
|
|
22
|
-
# Make sure we have someone to send to
|
23
|
-
# TODO need to test setting the options but filling with nil
|
22
|
+
# Make sure we have someone to send to and its not blank
|
24
23
|
has_sender = to_options.select { |option| options[option].present? }.present?
|
25
24
|
raise "Email instance has no sender (to,cc,bcc were all blank)" unless has_sender
|
26
25
|
|
26
|
+
|
27
27
|
# Make sure that all options passed map to a accessor so we don't errantly
|
28
28
|
# think we are passing something correctly and really its getting silently
|
29
29
|
# ignored
|
@@ -54,25 +54,39 @@ module MailSpy
|
|
54
54
|
end
|
55
55
|
|
56
56
|
#Create the email
|
57
|
-
email = MailSpy::Email.
|
57
|
+
email = MailSpy::Email.new(options)
|
58
|
+
|
59
|
+
# Ensure we have the template for the email on s3
|
60
|
+
raise "Missing html template" unless email.html_erb.present?
|
61
|
+
raise "Missing text template" unless email.text_erb.present?
|
58
62
|
|
59
|
-
|
63
|
+
email.save!
|
64
|
+
|
65
|
+
# Enable sendgrid specific enhancements
|
66
|
+
# Must happen after the email has been saved for the id
|
60
67
|
if esp.options[:enable_sendgrid_event_tracking].present?
|
61
68
|
header = MailSpy::Sendgrid::SmtpApiHeader.new
|
62
69
|
header.setUniqueArgs({:eid => email.id.to_s})
|
63
70
|
email.headers = {'X-SMTPAPI' => header.asJSON}.merge(email.headers)
|
64
71
|
end
|
65
|
-
|
66
|
-
email.save!
|
67
72
|
email
|
68
73
|
end
|
69
74
|
|
70
75
|
# ------------------------------------------- SEND OUTSTANDING EMAILS
|
71
76
|
# Batches through all the emails that were scheduled and have come due
|
72
|
-
# sends them out (step many at a time)
|
77
|
+
# sends them out (step many at a time). Don't thread this method, instead
|
78
|
+
# use the parameters to control concurrency
|
73
79
|
def send_outstanding_emails(step=100, num_threads=50)
|
80
|
+
success = false
|
74
81
|
raise "No Email service providers installed" unless MailSpy.esps.present?
|
75
82
|
|
83
|
+
return if MailSpy::ProcessLog.currently_processing?
|
84
|
+
current_process = MailSpy::ProcessLog.create!(
|
85
|
+
{
|
86
|
+
:start => Time.now,
|
87
|
+
:running => true,
|
88
|
+
})
|
89
|
+
|
76
90
|
wq = WorkQueue.new(num_threads, step*2)
|
77
91
|
current_time = DateTime.now
|
78
92
|
offset = 0
|
@@ -87,7 +101,7 @@ module MailSpy
|
|
87
101
|
|
88
102
|
while true
|
89
103
|
emails = MailSpy::Email.
|
90
|
-
limit(step).offset(offset).
|
104
|
+
limit(step).offset(offset).asc(:_id).
|
91
105
|
where(:schedule_at.lte => current_time, :sent => false, :failed => false).collect
|
92
106
|
break if emails.count <= 0 #returns enumerator which is never blank
|
93
107
|
emails.each do |email|
|
@@ -104,13 +118,25 @@ module MailSpy
|
|
104
118
|
end
|
105
119
|
end
|
106
120
|
end
|
121
|
+
|
107
122
|
# We must join here otherwise the next loop email lookup will be in a
|
108
123
|
# race condition with the results of our worker_queue.
|
109
124
|
wq.join
|
110
125
|
offset += step
|
111
126
|
end
|
112
127
|
|
113
|
-
|
128
|
+
success = true
|
129
|
+
return sent
|
130
|
+
|
131
|
+
ensure
|
132
|
+
if current_process
|
133
|
+
end_time = Time.now
|
134
|
+
current_process.end = end_time
|
135
|
+
current_process.seconds_elapsed = end_time.to_i - current_process.start.to_i
|
136
|
+
current_process.running = false
|
137
|
+
current_process.success = success
|
138
|
+
current_process.save!
|
139
|
+
end
|
114
140
|
end
|
115
141
|
|
116
142
|
|
data/lib/mail_spy/version.rb
CHANGED
data/test/dummy/db/seeds.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
(0..10).each do |i|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
2
|
+
3.times.each do
|
3
|
+
MailSpy::Email.create!(
|
4
|
+
{
|
5
|
+
:email_address => "trcarden@gmail.com",
|
6
|
+
:user_id => 1,
|
7
|
+
:campaign => "testCampaign#{i%2}",
|
8
|
+
:stream => "testStream#{i}",
|
9
|
+
:component => "a",
|
10
|
+
:email_service_provider => 'sendgrid',
|
11
|
+
:actions => [
|
12
|
+
{:action_type => "open"},
|
13
|
+
{:action_type => "delivered"}
|
14
|
+
]
|
15
|
+
}
|
16
|
+
)
|
17
|
+
end
|
15
18
|
end
|
16
19
|
|