smailer 0.7.8 → 0.8.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.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/CHANGELOG.md +202 -0
- data/Gemfile +4 -3
- data/Gemfile.lock +16 -12
- data/README.md +107 -73
- data/generators/smailer/templates/migration.rb.erb +65 -47
- data/lib/generators/smailer/templates/migration.rb.erb +65 -47
- data/lib/smailer/models.rb +3 -2
- data/lib/smailer/models/{mail_campaign_attachment.rb → mail_attachment.rb} +3 -5
- data/lib/smailer/models/mail_campaign.rb +15 -4
- data/lib/smailer/models/mail_template.rb +13 -0
- data/lib/smailer/models/queued_mail.rb +51 -7
- data/lib/smailer/tasks/send.rb +2 -2
- data/lib/smailer/version.rb +2 -2
- data/setup-test-db +14 -0
- data/spec/factories/common.rb +4 -0
- data/spec/factories/models.rb +26 -0
- data/spec/features/issuing_a_newsletter_spec.rb +52 -0
- data/spec/features/sending_oneoff_emails.rb +42 -0
- data/spec/models/mail_campaign_spec.rb +28 -0
- data/spec/models/queued_mail_spec.rb +114 -0
- data/spec/spec_helper.rb +22 -4
- data/upgrading/migrations/smailer_v0_7_3_to_v0_8_0.rb +106 -0
- metadata +13 -6
- data/Guardfile +0 -14
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/models/mail_key_spec.rb +0 -18
data/lib/smailer/tasks/send.rb
CHANGED
@@ -50,7 +50,7 @@ module Smailer
|
|
50
50
|
from queue_item.from
|
51
51
|
to queue_item.to
|
52
52
|
subject queue_item.subject
|
53
|
-
queue_item.
|
53
|
+
queue_item.attachments.each do |attachment|
|
54
54
|
cached_attachments[attachment.id] ||= attachment.body
|
55
55
|
add_file :filename => attachment.filename,
|
56
56
|
:content => cached_attachments[attachment.id]
|
@@ -114,4 +114,4 @@ module Smailer
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
-
end
|
117
|
+
end
|
data/lib/smailer/version.rb
CHANGED
data/setup-test-db
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :mailing_list, class: Smailer::Models::MailingList do
|
3
|
+
name { "Mailing List #{generate(:name)}" }
|
4
|
+
end
|
5
|
+
|
6
|
+
factory :mail_template, class: Smailer::Models::MailTemplate do
|
7
|
+
from { generate(:email) }
|
8
|
+
subject 'Hi there'
|
9
|
+
body_html '<h1>Hi there</h1>'
|
10
|
+
body_text 'Hi there'
|
11
|
+
end
|
12
|
+
|
13
|
+
factory :mail_campaign, class: Smailer::Models::MailCampaign do
|
14
|
+
association :mailing_list
|
15
|
+
|
16
|
+
after(:build) do |mail_campaign|
|
17
|
+
mail_campaign.mail_template ||= FactoryGirl.build(:mail_template)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
factory :queued_mail, class: Smailer::Models::QueuedMail do
|
22
|
+
association :mail_campaign
|
23
|
+
|
24
|
+
to { generate(:email) }
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'Issuing a newsletter' do
|
4
|
+
describe 'the example from the readme' do
|
5
|
+
before do
|
6
|
+
# Required setup not from the readme
|
7
|
+
FactoryGirl.create(:mailing_list)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'works as expected' do
|
11
|
+
# locate the mailing list we'll be sending to
|
12
|
+
list = Smailer::Models::MailingList.first
|
13
|
+
|
14
|
+
# create a corresponding mail campaign
|
15
|
+
campaign_params = {
|
16
|
+
:from => 'noreply@example.org',
|
17
|
+
:subject => 'My First Campaign!',
|
18
|
+
:body_html => '<h1>Hello</h1><p>World</p>',
|
19
|
+
:body_text => 'Hello, world!',
|
20
|
+
:mailing_list_id => list.id,
|
21
|
+
}
|
22
|
+
campaign = Smailer::Models::MailCampaign.new campaign_params
|
23
|
+
campaign.add_unsubscribe_method :all
|
24
|
+
|
25
|
+
# Add attachments
|
26
|
+
campaign.add_attachment 'attachment.pdf', 'url_or_file_path_to_attachment'
|
27
|
+
|
28
|
+
campaign.save!
|
29
|
+
|
30
|
+
# enqueue mails to be sent out
|
31
|
+
subscribers = %w[
|
32
|
+
subscriber@domain.com
|
33
|
+
office@company.com
|
34
|
+
contact@store.com
|
35
|
+
]
|
36
|
+
subscribers.each do |subscriber|
|
37
|
+
campaign.queued_mails.create! :to => subscriber
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
41
|
+
expect(Smailer::Models::MailTemplate.count).to eq(1)
|
42
|
+
expect(Smailer::Models::MailAttachment.count).to eq(1)
|
43
|
+
expect(Smailer::Models::QueuedMail.count).to eq(3)
|
44
|
+
|
45
|
+
expect(campaign.from).to eq(campaign_params[:from])
|
46
|
+
expect(campaign.subject).to eq(campaign_params[:subject])
|
47
|
+
expect(campaign.body_html).to eq(campaign_params[:body_html])
|
48
|
+
expect(campaign.body_text).to eq(campaign_params[:body_text])
|
49
|
+
expect(campaign.mailing_list_id).to eq(campaign_params[:mailing_list_id])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'Sending one-off emails' do
|
4
|
+
describe 'the example from the readme' do
|
5
|
+
before do
|
6
|
+
# Required setup not from the readme
|
7
|
+
FactoryGirl.create(:mail_campaign)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'works as expected' do
|
11
|
+
campaign = Smailer::Models::MailCampaign.first
|
12
|
+
|
13
|
+
# The mail template is copied from the campaign and then you make you changes
|
14
|
+
# e.g. here the subject and from are copied from the campaign
|
15
|
+
campaign.queued_mails.create! :to => 'subscriber@domain.com', :body_html => '<h1>my custom body</h1>', :body_text => 'my custom body'
|
16
|
+
|
17
|
+
# if you change the campaign now it won't change the one-off queued_mails
|
18
|
+
|
19
|
+
# sending two mails to the same person
|
20
|
+
campaign.queued_mails.create! :to => 'subscriber@domain.com', :body_html => '<h1>second custom body</h1>', :body_text => 'second custom body', require_uniqueness => false
|
21
|
+
|
22
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
23
|
+
expect(Smailer::Models::MailTemplate.count).to eq(3) # 1 for the campaign and 2 for the one-off emails
|
24
|
+
expect(Smailer::Models::MailAttachment.count).to eq(0)
|
25
|
+
expect(Smailer::Models::QueuedMail.count).to eq(2)
|
26
|
+
|
27
|
+
first_mail = campaign.queued_mails.first
|
28
|
+
|
29
|
+
expect(first_mail.from).to eq(campaign.from)
|
30
|
+
expect(first_mail.subject).to eq(campaign.subject)
|
31
|
+
expect(first_mail.body_html).to eq('<h1>my custom body</h1>')
|
32
|
+
expect(first_mail.body_text).to eq('my custom body')
|
33
|
+
|
34
|
+
second_mail = campaign.queued_mails.last
|
35
|
+
|
36
|
+
expect(second_mail.from).to eq(campaign_params.from)
|
37
|
+
expect(second_mail.subject).to eq(campaign_params.subject)
|
38
|
+
expect(second_mail.body_html).to eq('<h1>second custom body</h1>')
|
39
|
+
expect(second_mail.body_text).to eq('second custom body')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Smailer::Models::MailCampaign do
|
4
|
+
describe '#save' do
|
5
|
+
it 'works as expected' do
|
6
|
+
mail_campaign = Smailer::Models::MailCampaign.new
|
7
|
+
|
8
|
+
mail_campaign.mailing_list = FactoryGirl.create(:mailing_list)
|
9
|
+
|
10
|
+
mail_campaign.from = '"test" <test@example.com>'
|
11
|
+
mail_campaign.subject = 'This is my test'
|
12
|
+
mail_campaign.body_html = 'Hello html'
|
13
|
+
mail_campaign.body_text = 'Hello text'
|
14
|
+
|
15
|
+
mail_campaign.add_attachment 'foo.pdf', '/tmp/foo.pdf'
|
16
|
+
|
17
|
+
expect(Smailer::Models::MailCampaign.count).to eq(0)
|
18
|
+
expect(Smailer::Models::MailTemplate.count).to eq(0)
|
19
|
+
expect(Smailer::Models::MailAttachment.count).to eq(0)
|
20
|
+
|
21
|
+
mail_campaign.save!
|
22
|
+
|
23
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
24
|
+
expect(Smailer::Models::MailTemplate.count).to eq(1)
|
25
|
+
expect(Smailer::Models::MailAttachment.count).to eq(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Smailer::Models::QueuedMail do
|
4
|
+
describe '#save' do
|
5
|
+
it 'could be made only with mail_campaign and to (recipient)' do
|
6
|
+
mail_campaign = FactoryGirl.create(:mail_campaign)
|
7
|
+
|
8
|
+
queued_mail = Smailer::Models::QueuedMail.new
|
9
|
+
|
10
|
+
queued_mail.mail_campaign = mail_campaign
|
11
|
+
queued_mail.to = 'test@example.com'
|
12
|
+
|
13
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
14
|
+
expect(Smailer::Models::MailTemplate.count).to eq(1)
|
15
|
+
expect(Smailer::Models::QueuedMail.count).to eq(0)
|
16
|
+
|
17
|
+
queued_mail.save!
|
18
|
+
|
19
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
20
|
+
expect(Smailer::Models::MailTemplate.count).to eq(1)
|
21
|
+
expect(Smailer::Models::QueuedMail.count).to eq(1)
|
22
|
+
|
23
|
+
queued_mail.reload
|
24
|
+
|
25
|
+
expect(queued_mail.to).to eq('test@example.com')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'would create its own template if you change any of the template attributes and will copy the mail_campaign template' do
|
29
|
+
mail_campaign = FactoryGirl.create(:mail_campaign)
|
30
|
+
mail_campaign.add_attachment 'foo.pdf', '/tmp/foo.pdf'
|
31
|
+
mail_campaign.save!
|
32
|
+
|
33
|
+
queued_mail = Smailer::Models::QueuedMail.new
|
34
|
+
|
35
|
+
queued_mail.mail_campaign = mail_campaign
|
36
|
+
queued_mail.to = 'text@example.com'
|
37
|
+
|
38
|
+
queued_mail.from = 'sender@example.com'
|
39
|
+
|
40
|
+
queued_mail.save!
|
41
|
+
|
42
|
+
mail_campaign.reload
|
43
|
+
queued_mail.reload
|
44
|
+
|
45
|
+
expect(queued_mail.from).to eq('sender@example.com')
|
46
|
+
expect(queued_mail.body_html).to eq(mail_campaign.body_html)
|
47
|
+
expect(queued_mail.body_text).to eq(mail_campaign.body_text)
|
48
|
+
expect(queued_mail.subject).to eq(mail_campaign.subject)
|
49
|
+
|
50
|
+
expect(queued_mail.attachments).to be_present
|
51
|
+
expect(mail_campaign.attachments).to be_present
|
52
|
+
expect(queued_mail.attachments.first.path).to eq(mail_campaign.attachments.first.path)
|
53
|
+
expect(queued_mail.attachments.first.filename).to eq(mail_campaign.attachments.first.filename)
|
54
|
+
|
55
|
+
expect(queued_mail.mail_template).to_not eq(mail_campaign.mail_template)
|
56
|
+
expect(queued_mail.attachments.first).to_not eq(mail_campaign.attachments.first)
|
57
|
+
|
58
|
+
expect(Smailer::Models::MailCampaign.count).to eq(1)
|
59
|
+
expect(Smailer::Models::MailTemplate.count).to eq(2)
|
60
|
+
expect(Smailer::Models::MailAttachment.count).to eq(2)
|
61
|
+
expect(Smailer::Models::QueuedMail.count).to eq(1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#key' do
|
66
|
+
it 'is unique per email' do
|
67
|
+
mail_campaign = FactoryGirl.create(:mail_campaign)
|
68
|
+
|
69
|
+
queued_mail_1 = Smailer::Models::QueuedMail.new
|
70
|
+
queued_mail_1.mail_campaign = mail_campaign
|
71
|
+
queued_mail_1.to = 'text@example.com'
|
72
|
+
|
73
|
+
queued_mail_2 = Smailer::Models::QueuedMail.new
|
74
|
+
queued_mail_2.mail_campaign = mail_campaign
|
75
|
+
queued_mail_2.to = 'text@example.com'
|
76
|
+
|
77
|
+
expect(queued_mail_1.key).to_not eq(queued_mail_2.key)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#require_uniqueness' do
|
82
|
+
it 'is required by default' do
|
83
|
+
mail_campaign = FactoryGirl.create(:mail_campaign)
|
84
|
+
|
85
|
+
queued_mail_1 = Smailer::Models::QueuedMail.new
|
86
|
+
queued_mail_1.mail_campaign = mail_campaign
|
87
|
+
queued_mail_1.to = 'text@example.com'
|
88
|
+
queued_mail_1.save!
|
89
|
+
|
90
|
+
queued_mail_2 = Smailer::Models::QueuedMail.new
|
91
|
+
queued_mail_2.mail_campaign = mail_campaign
|
92
|
+
queued_mail_2.to = 'text@example.com'
|
93
|
+
|
94
|
+
expect(queued_mail_2.save).to eq(false)
|
95
|
+
expect(queued_mail_2.errors[:to]).to be_present
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'could be turned off by setting it to false' do
|
99
|
+
mail_campaign = FactoryGirl.create(:mail_campaign)
|
100
|
+
|
101
|
+
queued_mail_1 = Smailer::Models::QueuedMail.new
|
102
|
+
queued_mail_1.mail_campaign = mail_campaign
|
103
|
+
queued_mail_1.to = 'text@example.com'
|
104
|
+
queued_mail_1.save!
|
105
|
+
|
106
|
+
queued_mail_2 = Smailer::Models::QueuedMail.new
|
107
|
+
queued_mail_2.mail_campaign = mail_campaign
|
108
|
+
queued_mail_2.to = 'text@example.com'
|
109
|
+
queued_mail_2.require_uniqueness = false
|
110
|
+
|
111
|
+
expect(queued_mail_2.save).to eq(true)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,6 +11,9 @@ Spork.prefork do
|
|
11
11
|
# in spec/support/ and its subdirectories.
|
12
12
|
Dir[File.expand_path('../../spec/support/**/*.rb', __FILE__)].each {|f| require f }
|
13
13
|
|
14
|
+
FactoryGirl.definition_file_paths = [File.expand_path('../../spec/factories/', __FILE__)]
|
15
|
+
FactoryGirl.find_definitions
|
16
|
+
|
14
17
|
# Checks for pending migrations before tests are run.
|
15
18
|
# If you are not using ActiveRecord, you can remove this line.
|
16
19
|
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
@@ -43,11 +46,26 @@ Spork.prefork do
|
|
43
46
|
# --seed 1234
|
44
47
|
config.order = "random"
|
45
48
|
|
46
|
-
config.before(:suite)
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
config.before(:suite) do
|
50
|
+
DatabaseCleaner.clean_with(:truncation)
|
51
|
+
|
52
|
+
begin
|
53
|
+
DatabaseCleaner.start
|
54
|
+
FactoryGirl.lint
|
55
|
+
ensure
|
56
|
+
DatabaseCleaner.clean
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
config.before(:each) do
|
61
|
+
DatabaseCleaner.strategy = :transaction
|
62
|
+
|
63
|
+
DatabaseCleaner.start
|
64
|
+
end
|
50
65
|
|
66
|
+
config.after(:each) do
|
67
|
+
DatabaseCleaner.clean
|
68
|
+
end
|
51
69
|
end
|
52
70
|
end
|
53
71
|
|
@@ -0,0 +1,106 @@
|
|
1
|
+
class SmailerV073ToV080 < ActiveRecord::Migration
|
2
|
+
class MailCampaign < ActiveRecord::Base
|
3
|
+
has_one :mail_template
|
4
|
+
has_many :mail_attachments
|
5
|
+
end
|
6
|
+
|
7
|
+
class MailTemplate < ActiveRecord::Base
|
8
|
+
belongs_to :mail_campaign
|
9
|
+
belongs_to :queued_mail, :dependent => :destroy
|
10
|
+
|
11
|
+
has_many :mail_attachments
|
12
|
+
end
|
13
|
+
|
14
|
+
class MailAttachment < ActiveRecord::Base
|
15
|
+
belongs_to :mail_campaign
|
16
|
+
belongs_to :mail_template
|
17
|
+
end
|
18
|
+
|
19
|
+
class QueuedMail < ActiveRecord::Base
|
20
|
+
has_one :queued_mail
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.up
|
24
|
+
create_table :mail_templates do |t|
|
25
|
+
t.references :mail_campaign
|
26
|
+
t.references :queued_mail
|
27
|
+
|
28
|
+
t.string :from
|
29
|
+
t.string :subject
|
30
|
+
t.text :body_html
|
31
|
+
t.text :body_text
|
32
|
+
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
add_index :mail_templates, :mail_campaign_id
|
37
|
+
add_index :mail_templates, :queued_mail_id
|
38
|
+
|
39
|
+
rename_table :mail_campaign_attachments, :mail_attachments
|
40
|
+
|
41
|
+
add_column :mail_attachments, :mail_template_id, :integer
|
42
|
+
add_index :mail_attachments, :mail_template_id
|
43
|
+
|
44
|
+
MailCampaign.all.each do |mail_campaign|
|
45
|
+
mail_template = MailTemplate.new
|
46
|
+
|
47
|
+
mail_template.mail_campaign = mail_campaign
|
48
|
+
mail_template.mail_attachments = mail_campaign.mail_attachments
|
49
|
+
mail_template.from = mail_campaign.from
|
50
|
+
mail_template.subject = mail_campaign.subject
|
51
|
+
mail_template.body_html = mail_campaign.body_html
|
52
|
+
mail_template.body_text = mail_campaign.body_text
|
53
|
+
|
54
|
+
mail_template.save!
|
55
|
+
end
|
56
|
+
|
57
|
+
remove_column :mail_attachments, :mail_campaign_id
|
58
|
+
|
59
|
+
remove_column :mail_campaigns, :from
|
60
|
+
remove_column :mail_campaigns, :subject
|
61
|
+
remove_column :mail_campaigns, :body_html
|
62
|
+
remove_column :mail_campaigns, :body_text
|
63
|
+
|
64
|
+
add_column :queued_mails, :require_uniqueness, :boolean, :default => true
|
65
|
+
|
66
|
+
remove_index :queued_mails, :name => 'index_queued_mails_on_mail_campain_id_and_to'
|
67
|
+
add_index :queued_mails, [:mail_campaign_id, :to, :require_uniqueness], :name => 'index_queued_mails_uniqueness_for_to', :unique => true
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.down
|
71
|
+
remove_index :queued_mails, :name => 'index_queued_mails_uniqueness_for_to'
|
72
|
+
add_index :queued_mails, [:mail_campaign_id, :to], :name => 'index_queued_mails_on_mail_campain_id_and_to', :unique => true
|
73
|
+
|
74
|
+
QueuedMail.destroy_all('require_uniqueness is null')
|
75
|
+
|
76
|
+
remove_column :queued_mails, :require_uniqueness
|
77
|
+
|
78
|
+
MailTemplate.destroy_all('queued_mail_id is not null')
|
79
|
+
|
80
|
+
add_column :mail_campaigns, :from, :string
|
81
|
+
add_column :mail_campaigns, :subject, :string
|
82
|
+
add_column :mail_campaigns, :body_html, :text
|
83
|
+
add_column :mail_campaigns, :body_text, :text
|
84
|
+
|
85
|
+
add_column :mail_attachments, :mail_campaign_id, :integer
|
86
|
+
add_index :mail_attachments, :mail_campaign_id
|
87
|
+
|
88
|
+
MailCampaign.all.each do |mail_campaign|
|
89
|
+
mail_template = mail_campaign.mail_template
|
90
|
+
|
91
|
+
mail_campaign.mail_attachments = mail_template.mail_attachments
|
92
|
+
|
93
|
+
mail_campaign.from = mail_template.from
|
94
|
+
mail_campaign.subject = mail_template.subject
|
95
|
+
mail_campaign.body_html = mail_template.body_html
|
96
|
+
mail_campaign.body_text = mail_template.body_text
|
97
|
+
|
98
|
+
mail_campaign.save!
|
99
|
+
end
|
100
|
+
|
101
|
+
remove_column :mail_attachments, :mail_template_id
|
102
|
+
rename_table :mail_attachments, :mail_campaign_attachments
|
103
|
+
|
104
|
+
drop_table :mail_templates
|
105
|
+
end
|
106
|
+
end
|