mixpanel-mail 0.1.1 → 0.1.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.
- data/Gemfile +2 -1
- data/Gemfile.lock +49 -1
- data/lib/action_mailer/mixpanel_interceptor.rb +15 -13
- data/lib/mixpanel-mail.rb +3 -2
- data/lib/mixpanel_mail/version.rb +1 -1
- data/spec/action_mailer/mixpanel_interceptor_spec.rb +108 -0
- data/spec/mixpanel/mail_spec.rb +13 -12
- data/spec/support/webmock.rb +7 -0
- metadata +6 -4
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in mixpanel-mail.gemspec
|
4
4
|
gemspec
|
@@ -10,4 +10,5 @@ gem 'rake'
|
|
10
10
|
group :development do
|
11
11
|
gem "rspec", "~> 2.6.0"
|
12
12
|
gem "webmock", "~> 1.7.4"
|
13
|
+
gem 'actionmailer', '~> 3.1.0'
|
13
14
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,55 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mixpanel-mail (0.1.
|
4
|
+
mixpanel-mail (0.1.2)
|
5
5
|
multi_json
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
+
actionmailer (3.1.0)
|
11
|
+
actionpack (= 3.1.0)
|
12
|
+
mail (~> 2.3.0)
|
13
|
+
actionpack (3.1.0)
|
14
|
+
activemodel (= 3.1.0)
|
15
|
+
activesupport (= 3.1.0)
|
16
|
+
builder (~> 3.0.0)
|
17
|
+
erubis (~> 2.7.0)
|
18
|
+
i18n (~> 0.6)
|
19
|
+
rack (~> 1.3.2)
|
20
|
+
rack-cache (~> 1.0.3)
|
21
|
+
rack-mount (~> 0.8.2)
|
22
|
+
rack-test (~> 0.6.1)
|
23
|
+
sprockets (~> 2.0.0)
|
24
|
+
activemodel (3.1.0)
|
25
|
+
activesupport (= 3.1.0)
|
26
|
+
bcrypt-ruby (~> 3.0.0)
|
27
|
+
builder (~> 3.0.0)
|
28
|
+
i18n (~> 0.6)
|
29
|
+
activesupport (3.1.0)
|
30
|
+
multi_json (~> 1.0)
|
10
31
|
addressable (2.2.6)
|
32
|
+
bcrypt-ruby (3.0.1)
|
33
|
+
builder (3.0.0)
|
11
34
|
crack (0.3.1)
|
12
35
|
diff-lcs (1.1.3)
|
36
|
+
erubis (2.7.0)
|
37
|
+
hike (1.2.1)
|
38
|
+
i18n (0.6.0)
|
39
|
+
mail (2.3.0)
|
40
|
+
i18n (>= 0.4.0)
|
41
|
+
mime-types (~> 1.16)
|
42
|
+
treetop (~> 1.4.8)
|
43
|
+
mime-types (1.16)
|
13
44
|
multi_json (1.0.3)
|
45
|
+
polyglot (0.3.2)
|
46
|
+
rack (1.3.3)
|
47
|
+
rack-cache (1.0.3)
|
48
|
+
rack (>= 0.4)
|
49
|
+
rack-mount (0.8.3)
|
50
|
+
rack (>= 1.0.0)
|
51
|
+
rack-test (0.6.1)
|
52
|
+
rack (>= 1.0)
|
14
53
|
rake (0.9.2)
|
15
54
|
rspec (2.6.0)
|
16
55
|
rspec-core (~> 2.6.0)
|
@@ -20,6 +59,14 @@ GEM
|
|
20
59
|
rspec-expectations (2.6.0)
|
21
60
|
diff-lcs (~> 1.1.2)
|
22
61
|
rspec-mocks (2.6.0)
|
62
|
+
sprockets (2.0.0)
|
63
|
+
hike (~> 1.2)
|
64
|
+
rack (~> 1.0)
|
65
|
+
tilt (!= 1.3.0, ~> 1.1)
|
66
|
+
tilt (1.3.3)
|
67
|
+
treetop (1.4.10)
|
68
|
+
polyglot
|
69
|
+
polyglot (>= 0.3.1)
|
23
70
|
webmock (1.7.6)
|
24
71
|
addressable (> 2.2.5, ~> 2.2)
|
25
72
|
crack (>= 0.1.7)
|
@@ -28,6 +75,7 @@ PLATFORMS
|
|
28
75
|
ruby
|
29
76
|
|
30
77
|
DEPENDENCIES
|
78
|
+
actionmailer (~> 3.1.0)
|
31
79
|
mixpanel-mail!
|
32
80
|
rake
|
33
81
|
rspec (~> 2.6.0)
|
@@ -7,7 +7,8 @@ require 'digest/md5'
|
|
7
7
|
|
8
8
|
module ActionMailer
|
9
9
|
class MixpanelInterceptor
|
10
|
-
cattr_accessor :token
|
10
|
+
cattr_accessor :token, :logger
|
11
|
+
self.logger = Rails.logger if defined?(Rails)
|
11
12
|
|
12
13
|
class << self
|
13
14
|
def activate!(token)
|
@@ -16,35 +17,36 @@ module ActionMailer
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def delivering_email(mail)
|
19
|
-
#
|
20
|
-
return unless mail.header['mp_campaign']
|
21
|
-
|
22
|
-
# Skip Mixpanel if we don't have HTML
|
23
|
-
html = mail.html_part ? mail.html_part.body : nil
|
24
|
-
return unless html.present?
|
25
|
-
|
26
|
-
# Convert header options to mixpanel options
|
20
|
+
# Remove all the Mixpanel headers from the email
|
27
21
|
opts = ::Mixpanel::Mail::OPTIONS.inject({}) do |sum, key|
|
28
|
-
if
|
29
|
-
sum[key] = value
|
22
|
+
if field = pop_mp_header(mail, key)
|
23
|
+
sum[key] = field.value
|
30
24
|
end
|
31
25
|
sum
|
32
26
|
end
|
33
27
|
|
28
|
+
# Skip Mixpanel if the campaign is not specified
|
29
|
+
return unless opts['campaign']
|
30
|
+
|
31
|
+
# Skip Mixpanel if we don't have HTML
|
32
|
+
html = mail.html_part ? mail.html_part.decoded : nil
|
33
|
+
return unless html.present?
|
34
|
+
|
34
35
|
# Generate email distinct_id for Mixpanel
|
35
36
|
id = Digest::MD5.hexdigest(mail.header['To'].to_s)
|
36
37
|
|
37
38
|
begin
|
38
39
|
mail.html_part.body = mp_mail.add_tracking(id, html, opts)
|
39
40
|
rescue => e
|
40
|
-
Rails.logger.warn("Failed to Mixpanelize Mail: #{e}")
|
41
41
|
mail.html_part.body = html
|
42
|
+
logger.warn("Failed to Mixpanelize Mail: #{e}")
|
43
|
+
logger.debug(e.backtrace.join("\n"))
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
47
|
private
|
46
48
|
def mp_mail
|
47
|
-
@mixpanel_mail ||= Mixpanel::Mail.new(token
|
49
|
+
@mixpanel_mail ||= Mixpanel::Mail.new(token)
|
48
50
|
end
|
49
51
|
|
50
52
|
def pop_mp_header(mail, key)
|
data/lib/mixpanel-mail.rb
CHANGED
@@ -13,13 +13,14 @@ module Mixpanel
|
|
13
13
|
ENDPOINT = 'http://api.mixpanel.com/email'
|
14
14
|
ENDPOINT_URI = URI.parse(ENDPOINT)
|
15
15
|
OPTIONS = %w(campaign type properties redirect_host click_tracking)
|
16
|
+
DEFAULT_CAMPAIGN = 'default'
|
16
17
|
|
17
18
|
attr_accessor :params
|
18
19
|
|
19
|
-
def initialize(token,
|
20
|
+
def initialize(token, options = {})
|
20
21
|
@params = {}
|
21
22
|
params['token'] = token
|
22
|
-
params['campaign'] =
|
23
|
+
params['campaign'] = DEFAULT_CAMPAIGN
|
23
24
|
params.merge!(groom_options(options))
|
24
25
|
end
|
25
26
|
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'logger'
|
3
|
+
require 'mail'
|
4
|
+
require 'action_mailer'
|
5
|
+
require 'action_mailer/mixpanel_interceptor'
|
6
|
+
|
7
|
+
describe ActionMailer::MixpanelInterceptor do
|
8
|
+
MI = ActionMailer::MixpanelInterceptor
|
9
|
+
TOKEN = 'abcd123'
|
10
|
+
TO_ADDY = 'test@gemfury.com'
|
11
|
+
HTML_BODY = '<h1>HTML</h1>'
|
12
|
+
|
13
|
+
before do
|
14
|
+
MI.token = TOKEN
|
15
|
+
MI.logger = Logger.new($stdout)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '::delivering_email' do
|
19
|
+
before do
|
20
|
+
@mail = Mail::Message.new do
|
21
|
+
to TO_ADDY
|
22
|
+
body 'Hello World!'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should ignore mails without any MP options' do
|
27
|
+
MI.delivering_email(@mail)
|
28
|
+
a_post.should_not have_been_made
|
29
|
+
end
|
30
|
+
|
31
|
+
### Shared Examples for All Emails ###
|
32
|
+
shared_examples_for 'all emails' do
|
33
|
+
it 'should remove all Mixpanel headers' do
|
34
|
+
MI.delivering_email(@mail)
|
35
|
+
default_headers.keys do |key|
|
36
|
+
@mail.header[key].should be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
### Shared Examples for Emails for non-Mixpanel emails ###
|
42
|
+
shared_examples_for 'ignored Mixpanel email' do
|
43
|
+
it_should_behave_like 'all emails'
|
44
|
+
it 'should not make a Mixpanel request' do
|
45
|
+
MI.delivering_email(@mail)
|
46
|
+
a_post.should_not have_been_made
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'with MP headers without mp_campaign' do
|
51
|
+
before do
|
52
|
+
apply_headers(@mail, default_headers(:campaign => nil))
|
53
|
+
@mail.html_part { body(HTML_BODY) }
|
54
|
+
end
|
55
|
+
|
56
|
+
it_should_behave_like 'ignored Mixpanel email'
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'with Mixpanel headers' do
|
60
|
+
before do
|
61
|
+
apply_headers(@mail, default_headers)
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'without HTML email part' do
|
65
|
+
it_should_behave_like 'ignored Mixpanel email'
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'with HTML email part' do
|
69
|
+
before do
|
70
|
+
@mail.html_part { body(HTML_BODY) }
|
71
|
+
stub_post
|
72
|
+
end
|
73
|
+
|
74
|
+
it_should_behave_like 'all emails'
|
75
|
+
|
76
|
+
it 'should make a request to Mixpanel' do
|
77
|
+
params = Mixpanel::Mail.new(TOKEN, default_params).params
|
78
|
+
params['distinct_id'] = Digest::MD5.hexdigest(TO_ADDY)
|
79
|
+
params['body'] = HTML_BODY
|
80
|
+
|
81
|
+
verify_mixpanel_requests(params) do
|
82
|
+
MI.delivering_email(@mail)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def apply_headers(mail, headers)
|
91
|
+
headers.each { |k, v| mail.header[k] = v }
|
92
|
+
end
|
93
|
+
|
94
|
+
def default_headers(headers = {})
|
95
|
+
out = {}
|
96
|
+
default_params(headers).each do |key, value|
|
97
|
+
out["mp_#{key}".to_sym] = value
|
98
|
+
end
|
99
|
+
out
|
100
|
+
end
|
101
|
+
|
102
|
+
def default_params(headers = {})
|
103
|
+
{ :campaign => 'my-test-campaign',
|
104
|
+
:properties => { :foo => :bar },
|
105
|
+
:redirect_host => 'mp.testhost.com',
|
106
|
+
:type => 'text' }.merge(headers)
|
107
|
+
end
|
108
|
+
end
|
data/spec/mixpanel/mail_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mixpanel::Mail do
|
4
|
-
TOKEN, CAMPAIGN = 'abcd123',
|
4
|
+
TOKEN, CAMPAIGN = 'abcd123', Mixpanel::Mail::DEFAULT_CAMPAIGN
|
5
5
|
|
6
|
-
it 'should intialize token & campaign' do
|
6
|
+
it 'should intialize token & default campaign' do
|
7
7
|
lambda {
|
8
8
|
mail = mp_mail
|
9
9
|
mail.params['token'].should eq(TOKEN)
|
@@ -88,7 +88,7 @@ describe Mixpanel::Mail do
|
|
88
88
|
|
89
89
|
private
|
90
90
|
def mp_mail(options = {})
|
91
|
-
::Mixpanel::Mail.new(TOKEN,
|
91
|
+
::Mixpanel::Mail.new(TOKEN, options)
|
92
92
|
end
|
93
93
|
|
94
94
|
def mp_option_check(key, value_expectations = {})
|
@@ -99,14 +99,15 @@ private
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def verify_request_with_options(options = {}, expectations = {})
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
'
|
110
|
-
|
102
|
+
expectations = expectations.merge(
|
103
|
+
'token' => TOKEN,
|
104
|
+
'campaign' => CAMPAIGN,
|
105
|
+
'distinct_id' => 'my-dist-id',
|
106
|
+
'body' => 'Hello World!')
|
107
|
+
|
108
|
+
verify_mixpanel_requests(expectations, 2) do
|
109
|
+
mp_mail(options).add_tracking('my-dist-id', 'Hello World!')
|
110
|
+
mp_mail.add_tracking('my-dist-id', 'Hello World!', options)
|
111
|
+
end
|
111
112
|
end
|
112
113
|
end
|
data/spec/support/webmock.rb
CHANGED
@@ -7,4 +7,11 @@
|
|
7
7
|
self.class.send(:define_method, "stub_#{method}") do
|
8
8
|
stub_request(method, Mixpanel::Mail::ENDPOINT)
|
9
9
|
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Allow to set expectations for a mixpanel request
|
13
|
+
def verify_mixpanel_requests(body = {}, num = 1, &block)
|
14
|
+
stub_post
|
15
|
+
block && block.call
|
16
|
+
a_post.with(:body => body).should have_been_made.times(num)
|
10
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixpanel-mail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
12
|
+
date: 2011-09-28 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
16
|
-
requirement: &
|
16
|
+
requirement: &70185098031860 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70185098031860
|
25
25
|
description: Helpers for Mixpanel Tracking in Emails
|
26
26
|
email:
|
27
27
|
- mrykov@gmail.com
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- lib/mixpanel_mail/vendor/active_support/core_ext/hash/slice.rb
|
41
41
|
- lib/mixpanel_mail/version.rb
|
42
42
|
- mixpanel-mail.gemspec
|
43
|
+
- spec/action_mailer/mixpanel_interceptor_spec.rb
|
43
44
|
- spec/mixpanel/mail_spec.rb
|
44
45
|
- spec/spec_helper.rb
|
45
46
|
- spec/support/webmock.rb
|
@@ -68,6 +69,7 @@ signing_key:
|
|
68
69
|
specification_version: 3
|
69
70
|
summary: Helpers for Mixpanel Tracking in Emails
|
70
71
|
test_files:
|
72
|
+
- spec/action_mailer/mixpanel_interceptor_spec.rb
|
71
73
|
- spec/mixpanel/mail_spec.rb
|
72
74
|
- spec/spec_helper.rb
|
73
75
|
- spec/support/webmock.rb
|