mailboxer 0.11.0 → 0.12.0.rc1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +4 -3
  4. data/Appraisals +6 -14
  5. data/Gemfile +1 -1
  6. data/README.md +2 -2
  7. data/app/mailers/mailboxer/base_mailer.rb +14 -0
  8. data/app/mailers/{message_mailer.rb → mailboxer/message_mailer.rb} +9 -14
  9. data/app/mailers/mailboxer/notification_mailer.rb +17 -0
  10. data/app/models/mailboxer/conversation.rb +196 -0
  11. data/app/models/mailboxer/conversation/opt_out.rb +15 -0
  12. data/app/models/{mailbox.rb → mailboxer/mailbox.rb} +10 -10
  13. data/app/models/mailboxer/message.rb +49 -0
  14. data/app/models/{notification.rb → mailboxer/notification.rb} +44 -40
  15. data/app/models/{receipt.rb → mailboxer/receipt.rb} +12 -11
  16. data/app/views/{message_mailer → mailboxer/message_mailer}/new_message_email.html.erb +3 -3
  17. data/app/views/{message_mailer → mailboxer/message_mailer}/new_message_email.text.erb +2 -2
  18. data/app/views/{message_mailer → mailboxer/message_mailer}/reply_message_email.html.erb +3 -3
  19. data/app/views/{message_mailer → mailboxer/message_mailer}/reply_message_email.text.erb +2 -2
  20. data/app/views/{notification_mailer → mailboxer/notification_mailer}/new_notification_email.html.erb +0 -0
  21. data/app/views/{notification_mailer → mailboxer/notification_mailer}/new_notification_email.text.erb +0 -0
  22. data/db/migrate/20110511145103_create_mailboxer.rb +18 -14
  23. data/db/migrate/20131206080416_add_conversation_optout.rb +14 -0
  24. data/gemfiles/rails3.2.gemfile +2 -3
  25. data/gemfiles/rails4.0.gemfile +3 -4
  26. data/gemfiles/rails4.1.gemfile +7 -0
  27. data/lib/generators/mailboxer/install_generator.rb +1 -4
  28. data/lib/generators/mailboxer/namespacing_compatibility_generator.rb +22 -0
  29. data/lib/generators/mailboxer/templates/initializer.rb +8 -4
  30. data/lib/generators/mailboxer/templates/mailboxer_namespacing_compatibility.rb +24 -0
  31. data/lib/mailboxer.rb +7 -1
  32. data/lib/mailboxer/cleaner.rb +9 -0
  33. data/lib/mailboxer/engine.rb +1 -1
  34. data/lib/mailboxer/mail_dispatcher.rb +48 -0
  35. data/lib/mailboxer/models/messageable.rb +21 -20
  36. data/lib/mailboxer/version.rb +3 -0
  37. data/mailboxer.gemspec +16 -8
  38. data/spec/dummy/Gemfile +1 -1
  39. data/spec/dummy/app/models/duck.rb +2 -2
  40. data/spec/dummy/config/initializers/mailboxer.rb +4 -0
  41. data/spec/dummy/db/migrate/20120305103200_create_mailboxer.rb +18 -14
  42. data/spec/dummy/db/migrate/20131206080416_add_conversation_optout.rb +14 -0
  43. data/spec/dummy/db/schema.rb +30 -21
  44. data/spec/integration/message_and_receipt_spec.rb +212 -212
  45. data/spec/mailboxer/mail_dispatcher_spec.rb +114 -0
  46. data/spec/mailers/message_mailer_spec.rb +4 -4
  47. data/spec/mailers/notification_mailer_spec.rb +2 -2
  48. data/spec/models/conversation_spec.rb +148 -47
  49. data/spec/models/mailbox_spec.rb +50 -50
  50. data/spec/models/mailboxer_models_messageable_spec.rb +52 -52
  51. data/spec/models/message_spec.rb +1 -1
  52. data/spec/models/notification_spec.rb +50 -18
  53. data/spec/models/receipt_spec.rb +1 -1
  54. data/spec/spec_helper.rb +3 -0
  55. metadata +68 -57
  56. data/app/mailers/notification_mailer.rb +0 -21
  57. data/app/models/conversation.rb +0 -166
  58. data/app/models/message.rb +0 -68
  59. data/db/migrate/20110719110700_add_notified_object.rb +0 -17
  60. data/db/migrate/20110912163911_add_notification_code.rb +0 -13
  61. data/db/migrate/20111204163911_add_attachments.rb +0 -9
  62. data/db/migrate/20120813110712_rename_receipts_read.rb +0 -9
  63. data/db/migrate/20130305144212_add_global_notification_support.rb +0 -9
  64. data/gemfiles/rails3.0.gemfile +0 -8
  65. data/gemfiles/rails3.1.gemfile +0 -8
  66. data/lib/mailboxer/concerns/configurable_mailer.rb +0 -13
  67. data/spec/dummy/db/migrate/20120305103201_add_notified_object.rb +0 -17
  68. data/spec/dummy/db/migrate/20120305103202_add_notification_code.rb +0 -13
  69. data/spec/dummy/db/migrate/20120305103203_add_attachments.rb +0 -5
  70. data/spec/dummy/db/migrate/20120813110712_rename_receipts_read.rb +0 -9
  71. data/spec/dummy/db/migrate/20130305144212_add_global_notification_support.rb +0 -11
  72. data/spec/mailboxer/concerns/configurable_mailer_spec.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b22e110378d5da7e6e327c807f46a5f0475b2fa1
4
- data.tar.gz: bc9242e076e3a10d2e3d9ca1106a42200ca7bc12
3
+ metadata.gz: e699bff86b951b515780d88e719ae2b02eca59e7
4
+ data.tar.gz: 7024930841d1c7b675ecca3eab46767896fcc67c
5
5
  SHA512:
6
- metadata.gz: f67c3839eb84ce3153e7e9b1b50b012f80a1d17bdb56589e18279ba1043e3e4fc4f443c17b2ed9cff7a0e4bcbc9ebef10139bd63de67b520ac12f3fcd40bc05e
7
- data.tar.gz: 277d0c3921688613e407b095665d7d2b2afe783294f1500d9ba2a423c83460b5854711520a9cfaddcec876b864924c65136edcd78dbdad4fbbd8286eb5d5405f
6
+ metadata.gz: 81b0a14bd89091e70042fc95e215482bb3c64c2d352821f40c0da348b51eb0fa1d07c2d802bc73f933758f767e1b65c3f314e7741da3b8035c91607f10321848
7
+ data.tar.gz: d9e30049e35052c5253f3587239ce9dfb6568c9350056d82fb261ed9a9d20096aef578c1252c3f48353aa4f88688782e019ba187c37e448a73c8f5092224634e
data/.gitignore CHANGED
@@ -9,6 +9,7 @@ spec/dummy/.project
9
9
  spec/dummy/solr
10
10
  **.tmp_*
11
11
  Gemfile.lock
12
+ gemfiles/*.lock
12
13
  .idea
13
14
  .project
14
15
  .document
@@ -16,3 +17,4 @@ Gemfile.lock
16
17
  rdoc/
17
18
  doc/
18
19
  .yardoc/*
20
+ .rvmrc
data/.travis.yml CHANGED
@@ -2,10 +2,11 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
- - rbx-19mode
6
5
  - jruby-19mode
7
6
  gemfile:
8
- #- gemfiles/rails3.0.gemfile
9
- - gemfiles/rails3.1.gemfile
10
7
  - gemfiles/rails3.2.gemfile
11
8
  - gemfiles/rails4.0.gemfile
9
+ - gemfiles/rails4.1.gemfile
10
+ env:
11
+ global:
12
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
data/Appraisals CHANGED
@@ -1,19 +1,11 @@
1
- # appraise "rails3.0" do
2
- # gem "rails", "~> 3.0.15"
3
- # gem "mailboxer", :path => "../"
4
- # end
5
-
6
- appraise "rails3.1" do
7
- gem "rails", "~> 3.1.6"
8
- gem "mailboxer", :path => "../"
9
- end
10
-
11
1
  appraise "rails3.2" do
12
- gem "rails", "~> 3.2.6"
13
- gem "mailboxer", :path => "../"
2
+ gem "rails", "~> 3.2.17"
14
3
  end
15
4
 
16
5
  appraise "rails4.0" do
17
- gem "rails", ">=4.0.0"
18
- gem "mailboxer", :path => "../"
6
+ gem "rails", "~> 4.0.4"
7
+ end
8
+
9
+ appraise "rails4.1" do
10
+ gem "rails", "~> 4.1.0"
19
11
  end
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gemspec
3
+ gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Mailboxer 0.10.x [![](https://secure.travis-ci.org/ging/mailboxer.png)](http://travis-ci.org/ging/mailboxer) [![Gem Version](https://badge.fury.io/rb/mailboxer.png)](http://badge.fury.io/rb/mailboxer) [![](https://gemnasium.com/ging/mailboxer.png)](https://gemnasium.com/ging/mailboxer)
1
+ # Mailboxer [![Build Status](https://travis-ci.org/mailboxer/mailboxer.svg?branch=master)](https://travis-ci.org/mailboxer/mailboxer) [![Gem Version](https://badge.fury.io/rb/mailboxer.png)](http://badge.fury.io/rb/mailboxer) [![](https://gemnasium.com/ging/mailboxer.png)](https://gemnasium.com/ging/mailboxer)
2
2
 
3
3
  This project is based on the need for a private message system for [ging
4
4
  / social\_stream](https://github.com/ging/social_stream). Instead of creating our core message system heavily
@@ -41,7 +41,7 @@ gem 'mailboxer'
41
41
  Then run:
42
42
 
43
43
  ```sh
44
- $ bundle update
44
+ $ bundle install
45
45
  ```
46
46
 
47
47
  Run install script:
@@ -0,0 +1,14 @@
1
+ class Mailboxer::BaseMailer < ActionMailer::Base
2
+ default :from => Mailboxer.default_from
3
+
4
+ private
5
+
6
+ def set_subject(container)
7
+ @subject = container.subject.html_safe? ? container.subject : strip_tags(container.subject)
8
+ end
9
+
10
+ def strip_tags(text)
11
+ ::Mailboxer::Cleaner.instance.strip_tags(text)
12
+ end
13
+
14
+ end
@@ -1,5 +1,4 @@
1
- class MessageMailer < ActionMailer::Base
2
- default :from => Mailboxer.default_from
1
+ class Mailboxer::MessageMailer < Mailboxer::BaseMailer
3
2
  #Sends and email for indicating a new message or a reply to a receiver.
4
3
  #It calls new_message_email if notifing a new message and reply_message_email
5
4
  #when indicating a reply to an already created conversation.
@@ -11,27 +10,23 @@ class MessageMailer < ActionMailer::Base
11
10
  end
12
11
  end
13
12
 
14
- include ActionView::Helpers::SanitizeHelper
15
-
16
13
  #Sends an email for indicating a new message for the receiver
17
14
  def new_message_email(message,receiver)
18
- @message = message
15
+ @message = message
19
16
  @receiver = receiver
20
- subject = message.subject.to_s
21
- subject = strip_tags(subject) unless subject.html_safe?
22
- mail :to => receiver.send(Mailboxer.email_method,message),
23
- :subject => t('mailboxer.message_mailer.subject_new', :subject => subject),
17
+ set_subject(message)
18
+ mail :to => receiver.send(Mailboxer.email_method, message),
19
+ :subject => t('mailboxer.message_mailer.subject_new', :subject => @subject),
24
20
  :template_name => 'new_message_email'
25
21
  end
26
22
 
27
23
  #Sends and email for indicating a reply in an already created conversation
28
24
  def reply_message_email(message,receiver)
29
- @message = message
25
+ @message = message
30
26
  @receiver = receiver
31
- subject = message.subject.to_s
32
- subject = strip_tags(subject) unless subject.html_safe?
33
- mail :to => receiver.send(Mailboxer.email_method,message),
34
- :subject => t('mailboxer.message_mailer.subject_reply', :subject => subject),
27
+ set_subject(message)
28
+ mail :to => receiver.send(Mailboxer.email_method, message),
29
+ :subject => t('mailboxer.message_mailer.subject_reply', :subject => @subject),
35
30
  :template_name => 'reply_message_email'
36
31
  end
37
32
  end
@@ -0,0 +1,17 @@
1
+ class Mailboxer::NotificationMailer < Mailboxer::BaseMailer
2
+ #Sends and email for indicating a new notification to a receiver.
3
+ #It calls new_notification_email.
4
+ def send_email(notification, receiver)
5
+ new_notification_email(notification, receiver)
6
+ end
7
+
8
+ #Sends an email for indicating a new message for the receiver
9
+ def new_notification_email(notification, receiver)
10
+ @notification = notification
11
+ @receiver = receiver
12
+ set_subject(notification)
13
+ mail :to => receiver.send(Mailboxer.email_method, notification),
14
+ :subject => t('mailboxer.notification_mailer.subject', :subject => @subject),
15
+ :template_name => 'new_notification_email'
16
+ end
17
+ end
@@ -0,0 +1,196 @@
1
+ class Mailboxer::Conversation < ActiveRecord::Base
2
+ self.table_name = :mailboxer_conversations
3
+
4
+ attr_accessible :subject if Mailboxer.protected_attributes?
5
+
6
+ has_many :opt_outs, :dependent => :destroy, :class_name => "Mailboxer::Conversation::OptOut"
7
+ has_many :messages, :dependent => :destroy, :class_name => "Mailboxer::Message"
8
+ has_many :receipts, :through => :messages, :class_name => "Mailboxer::Receipt"
9
+
10
+ validates :subject, :presence => true,
11
+ :length => { :maximum => Mailboxer.subject_max_length }
12
+
13
+ before_validation :clean
14
+
15
+ scope :participant, lambda {|participant|
16
+ where('mailboxer_notifications.type'=> Mailboxer::Message.name).
17
+ order("mailboxer_conversations.updated_at DESC").
18
+ joins(:receipts).merge(Mailboxer::Receipt.recipient(participant)).uniq
19
+ }
20
+ scope :inbox, lambda {|participant|
21
+ participant(participant).merge(Mailboxer::Receipt.inbox.not_trash.not_deleted)
22
+ }
23
+ scope :sentbox, lambda {|participant|
24
+ participant(participant).merge(Mailboxer::Receipt.sentbox.not_trash.not_deleted)
25
+ }
26
+ scope :trash, lambda {|participant|
27
+ participant(participant).merge(Mailboxer::Receipt.trash)
28
+ }
29
+ scope :unread, lambda {|participant|
30
+ participant(participant).merge(Mailboxer::Receipt.is_unread)
31
+ }
32
+ scope :not_trash, lambda {|participant|
33
+ participant(participant).merge(Mailboxer::Receipt.not_trash)
34
+ }
35
+
36
+ #Mark the conversation as read for one of the participants
37
+ def mark_as_read(participant)
38
+ return unless participant
39
+ receipts_for(participant).mark_as_read
40
+ end
41
+
42
+ #Mark the conversation as unread for one of the participants
43
+ def mark_as_unread(participant)
44
+ return unless participant
45
+ receipts_for(participant).mark_as_unread
46
+ end
47
+
48
+ #Move the conversation to the trash for one of the participants
49
+ def move_to_trash(participant)
50
+ return unless participant
51
+ receipts_for(participant).move_to_trash
52
+ end
53
+
54
+ #Takes the conversation out of the trash for one of the participants
55
+ def untrash(participant)
56
+ return unless participant
57
+ receipts_for(participant).untrash
58
+ end
59
+
60
+ #Mark the conversation as deleted for one of the participants
61
+ def mark_as_deleted(participant)
62
+ return unless participant
63
+ deleted_receipts = receipts_for(participant).mark_as_deleted
64
+ if is_orphaned?
65
+ destroy
66
+ else
67
+ deleted_receipts
68
+ end
69
+ end
70
+
71
+ #Returns an array of participants
72
+ def recipients
73
+ return [] unless original_message
74
+ Array original_message.recipients
75
+ end
76
+
77
+ #Returns an array of participants
78
+ def participants
79
+ recipients
80
+ end
81
+
82
+ #Originator of the conversation.
83
+ def originator
84
+ @originator ||= self.original_message.sender
85
+ end
86
+
87
+ #First message of the conversation.
88
+ def original_message
89
+ @original_message ||= self.messages.order('created_at').first
90
+ end
91
+
92
+ #Sender of the last message.
93
+ def last_sender
94
+ @last_sender ||= self.last_message.sender
95
+ end
96
+
97
+ #Last message in the conversation.
98
+ def last_message
99
+ @last_message ||= self.messages.order('created_at DESC').first
100
+ end
101
+
102
+ #Returns the receipts of the conversation for one participants
103
+ def receipts_for(participant)
104
+ Mailboxer::Receipt.conversation(self).recipient(participant)
105
+ end
106
+
107
+ #Returns the number of messages of the conversation
108
+ def count_messages
109
+ Mailboxer::Message.conversation(self).count
110
+ end
111
+
112
+ #Returns true if the messageable is a participant of the conversation
113
+ def is_participant?(participant)
114
+ return false unless participant
115
+ receipts_for(participant).any?
116
+ end
117
+
118
+ #Adds a new participant to the conversation
119
+ def add_participant(participant)
120
+ messages = self.messages
121
+ messages.each do |message|
122
+ receipt = Mailboxer::Receipt.new
123
+ receipt.notification = message
124
+ receipt.is_read = false
125
+ receipt.receiver = participant
126
+ receipt.mailbox_type = 'inbox'
127
+ receipt.updated_at = message.updated_at
128
+ receipt.created_at = message.created_at
129
+ receipt.save
130
+ end
131
+ end
132
+
133
+ #Returns true if the participant has at least one trashed message of the conversation
134
+ def is_trashed?(participant)
135
+ return false unless participant
136
+ self.receipts_for(participant).trash.count != 0
137
+ end
138
+
139
+ #Returns true if the participant has deleted the conversation
140
+ def is_deleted?(participant)
141
+ return false unless participant
142
+ return self.receipts_for(participant).deleted.count == self.receipts_for(participant).count
143
+ end
144
+
145
+ #Returns true if both participants have deleted the conversation
146
+ def is_orphaned?
147
+ participants.reduce(true) do |is_orphaned, participant|
148
+ is_orphaned && is_deleted?(participant)
149
+ end
150
+ end
151
+
152
+ #Returns true if the participant has trashed all the messages of the conversation
153
+ def is_completely_trashed?(participant)
154
+ return false unless participant
155
+ receipts_for(participant).trash.count == receipts_for(participant).count
156
+ end
157
+
158
+ def is_read?(participant)
159
+ !is_unread?(participant)
160
+ end
161
+
162
+ #Returns true if the participant has at least one unread message of the conversation
163
+ def is_unread?(participant)
164
+ return false unless participant
165
+ receipts_for(participant).not_trash.is_unread.count != 0
166
+ end
167
+
168
+ # Creates a opt out object
169
+ # because by default all particpants are opt in
170
+ def opt_out(participant)
171
+ return unless has_subscriber?(participant)
172
+ opt_outs.create(:unsubscriber => participant)
173
+ end
174
+
175
+ # Destroys opt out object if any
176
+ # a participant outside of the discussion is, yet, not meant to optin
177
+ def opt_in(participant)
178
+ opt_outs.unsubscriber(participant).destroy_all
179
+ end
180
+
181
+ # tells if participant is opt in
182
+ def has_subscriber?(participant)
183
+ !opt_outs.unsubscriber(participant).any?
184
+ end
185
+
186
+ protected
187
+
188
+ #Use the default sanitize to clean the conversation subject
189
+ def clean
190
+ self.subject = sanitize subject
191
+ end
192
+
193
+ def sanitize(text)
194
+ ::Mailboxer::Cleaner.instance.sanitize(text)
195
+ end
196
+ end
@@ -0,0 +1,15 @@
1
+ module Mailboxer
2
+ class Conversation
3
+ class OptOut < ActiveRecord::Base
4
+ self.table_name = :mailboxer_conversation_opt_outs
5
+
6
+ belongs_to :conversation, :class_name => "Mailboxer::Conversation"
7
+ belongs_to :unsubscriber, :polymorphic => true
8
+
9
+ validates :unsubscriber, :presence => true
10
+
11
+ scope :unsubscriber, lambda { |entity| where(:unsubscriber_type => entity.class.base_class.name, :unsubscriber_id => entity.id) }
12
+
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,4 @@
1
- class Mailbox
1
+ class Mailboxer::Mailbox
2
2
  attr_accessor :type
3
3
  attr_reader :messageable
4
4
 
@@ -10,7 +10,7 @@ class Mailbox
10
10
  #Returns the notifications for the messageable
11
11
  def notifications(options = {})
12
12
  #:type => nil is a hack not to give Messages as Notifications
13
- notifs = Notification.recipient(@messageable).where(:type => nil).order("notifications.created_at DESC")
13
+ notifs = Mailboxer::Notification.recipient(@messageable).where(:type => nil).order("mailboxer_notifications.created_at DESC")
14
14
  if (options[:read].present? and options[:read]==false) or (options[:unread].present? and options[:unread]==true)
15
15
  notifs = notifs.unread
16
16
  end
@@ -31,18 +31,18 @@ class Mailbox
31
31
  #* :unread=true
32
32
  #
33
33
  def conversations(options = {})
34
- conv = Conversation.participant(@messageable)
34
+ conv = Mailboxer::Conversation.participant(@messageable)
35
35
 
36
36
  if options[:mailbox_type].present?
37
37
  case options[:mailbox_type]
38
38
  when 'inbox'
39
- conv = Conversation.inbox(@messageable)
39
+ conv = Mailboxer::Conversation.inbox(@messageable)
40
40
  when 'sentbox'
41
- conv = Conversation.sentbox(@messageable)
41
+ conv = Mailboxer::Conversation.sentbox(@messageable)
42
42
  when 'trash'
43
- conv = Conversation.trash(@messageable)
43
+ conv = Mailboxer::Conversation.trash(@messageable)
44
44
  when 'not_trash'
45
- conv = Conversation.not_trash(@messageable)
45
+ conv = Mailboxer::Conversation.not_trash(@messageable)
46
46
  end
47
47
  end
48
48
 
@@ -79,7 +79,7 @@ class Mailbox
79
79
 
80
80
  #Returns all the receipts of messageable, from Messages and Notifications
81
81
  def receipts(options = {})
82
- Receipt.where(options).recipient(@messageable)
82
+ Mailboxer::Receipt.where(options).recipient(@messageable)
83
83
  end
84
84
 
85
85
  #Deletes all the messages in the trash of messageable. NOT IMPLEMENTED.
@@ -113,9 +113,9 @@ class Mailbox
113
113
  #If object isn't one of the above, a nil will be returned
114
114
  def receipts_for(object)
115
115
  case object
116
- when Message, Notification
116
+ when Mailboxer::Message, Mailboxer::Notification
117
117
  object.receipt_for(@messageable)
118
- when Conversation
118
+ when Mailboxer::Conversation
119
119
  object.receipts_for(@messageable)
120
120
  end
121
121
  end
@@ -0,0 +1,49 @@
1
+ class Mailboxer::Message < Mailboxer::Notification
2
+ attr_accessible :attachment if Mailboxer.protected_attributes?
3
+ self.table_name = :mailboxer_notifications
4
+
5
+ belongs_to :conversation, :class_name => "Mailboxer::Conversation", :validate => true, :autosave => true
6
+ validates_presence_of :sender
7
+
8
+ class_attribute :on_deliver_callback
9
+ protected :on_deliver_callback
10
+ scope :conversation, lambda { |conversation|
11
+ where(:conversation_id => conversation.id)
12
+ }
13
+
14
+ mount_uploader :attachment, AttachmentUploader
15
+
16
+ class << self
17
+ #Sets the on deliver callback method.
18
+ def on_deliver(callback_method)
19
+ self.on_deliver_callback = callback_method
20
+ end
21
+ end
22
+
23
+ #Delivers a Message. USE NOT RECOMENDED.
24
+ #Use Mailboxer::Models::Message.send_message instead.
25
+ def deliver(reply = false, should_clean = true)
26
+ self.clean if should_clean
27
+
28
+ #Receiver receipts
29
+ temp_receipts = recipients.map { |r| build_receipt(r, 'inbox') }
30
+
31
+ #Sender receipt
32
+ sender_receipt = build_receipt(sender, 'sentbox', true)
33
+
34
+ temp_receipts << sender_receipt
35
+
36
+ if temp_receipts.all?(&:valid?)
37
+ temp_receipts.each(&:save!) #Save receipts
38
+
39
+ Mailboxer::MailDispatcher.new(self, recipients).call
40
+
41
+ conversation.touch if reply
42
+
43
+ self.recipients = nil
44
+
45
+ on_deliver_callback.call(self) if on_deliver_callback
46
+ end
47
+ sender_receipt
48
+ end
49
+ end