msg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +9 -0
  3. data/Rakefile +35 -0
  4. data/app/assets/images/msg/message.png +0 -0
  5. data/app/assets/images/msg/ping.png +0 -0
  6. data/app/assets/images/msg/sending.png +0 -0
  7. data/app/assets/javascripts/lib/jquery.peity.js +261 -0
  8. data/app/assets/javascripts/msg.js.coffee +6 -0
  9. data/app/assets/stylesheets/msg.css.sass +218 -0
  10. data/app/controllers/msg/bounces_controller.rb +67 -0
  11. data/app/controllers/msg/engine_controller.rb +23 -0
  12. data/app/controllers/msg/envelopes_controller.rb +22 -0
  13. data/app/controllers/msg/messages_controller.rb +85 -0
  14. data/app/controllers/msg/sendings_controller.rb +58 -0
  15. data/app/helpers/msg/msg_helper.rb +40 -0
  16. data/app/mailers/msg/devise_mailer.rb +20 -0
  17. data/app/mailers/msg/msg_mailer.rb +23 -0
  18. data/app/models/msg/bounce.rb +19 -0
  19. data/app/models/msg/envelope.rb +56 -0
  20. data/app/models/msg/message.rb +26 -0
  21. data/app/models/msg/sending.rb +54 -0
  22. data/app/views/layouts/msg/default.html.haml +30 -0
  23. data/app/views/layouts/msg/email.html.haml +10 -0
  24. data/app/views/msg/bounces/_listing.html.haml +5 -0
  25. data/app/views/msg/bounces/_report.html.haml +10 -0
  26. data/app/views/msg/bounces/index.html.haml +5 -0
  27. data/app/views/msg/devise_mailer/confirmation_instructions.en.html.haml +1 -0
  28. data/app/views/msg/devise_mailer/reset_password_instructions.en.html.haml +1 -0
  29. data/app/views/msg/envelopes/_listing.html.haml +5 -0
  30. data/app/views/msg/messages/_action_menu.html.haml +10 -0
  31. data/app/views/msg/messages/_form.html.haml +38 -0
  32. data/app/views/msg/messages/_instructions.html.haml +28 -0
  33. data/app/views/msg/messages/_message.html.haml +11 -0
  34. data/app/views/msg/messages/_saved_messages.html.haml +2 -0
  35. data/app/views/msg/messages/_transactional_messages.html.haml +3 -0
  36. data/app/views/msg/messages/edit.html.haml +7 -0
  37. data/app/views/msg/messages/index.html.haml +23 -0
  38. data/app/views/msg/messages/new.html.haml +7 -0
  39. data/app/views/msg/messages/preview.html.haml +4 -0
  40. data/app/views/msg/messages/show.html.haml +25 -0
  41. data/app/views/msg/msg_mailer/message_in_envelope.html.haml +2 -0
  42. data/app/views/msg/sendings/_form.html.haml +45 -0
  43. data/app/views/msg/sendings/_listing.html.haml +17 -0
  44. data/app/views/msg/sendings/_report.html.haml +8 -0
  45. data/app/views/msg/sendings/_sending.html.haml +22 -0
  46. data/app/views/msg/sendings/_sendings.html.haml +2 -0
  47. data/app/views/msg/sendings/index.html.haml +8 -0
  48. data/app/views/msg/sendings/new.html.haml +9 -0
  49. data/app/views/msg/sendings/review.html.haml +2 -0
  50. data/app/views/msg/sendings/show.html.haml +50 -0
  51. data/app/views/msg/shared/_toolbar.html.haml +17 -0
  52. data/config/cucumber.yml +8 -0
  53. data/config/locales/en.yml +76 -0
  54. data/config/routes.rb +26 -0
  55. data/db/migrate/20130320141926_msg_data.rb +54 -0
  56. data/db/migrate/20130327134754_sending_circumstances.rb +6 -0
  57. data/lib/msg.rb +88 -0
  58. data/lib/msg/engine.rb +23 -0
  59. data/lib/msg/receivers.rb +64 -0
  60. data/lib/msg/version.rb +3 -0
  61. data/lib/tasks/cucumber.rake +65 -0
  62. data/lib/tasks/msg_tasks.rake +4 -0
  63. data/spec/controllers/msg/bounces_controller_spec.rb +48 -0
  64. data/spec/controllers/msg/envelopes_controller_spec.rb +22 -0
  65. data/spec/controllers/msg/messages_controller_spec.rb +9 -0
  66. data/spec/controllers/msg/sendings_controller_spec.rb +47 -0
  67. data/spec/dummy/README.rdoc +261 -0
  68. data/spec/dummy/Rakefile +7 -0
  69. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  70. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  71. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  72. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  73. data/spec/dummy/app/models/user.rb +14 -0
  74. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  75. data/spec/dummy/config.ru +4 -0
  76. data/spec/dummy/config/application.rb +59 -0
  77. data/spec/dummy/config/boot.rb +10 -0
  78. data/spec/dummy/config/database.yml +25 -0
  79. data/spec/dummy/config/environment.rb +5 -0
  80. data/spec/dummy/config/environments/development.rb +37 -0
  81. data/spec/dummy/config/environments/production.rb +67 -0
  82. data/spec/dummy/config/environments/test.rb +41 -0
  83. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  84. data/spec/dummy/config/initializers/devise.rb +285 -0
  85. data/spec/dummy/config/initializers/inflections.rb +15 -0
  86. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  87. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  88. data/spec/dummy/config/initializers/session_store.rb +8 -0
  89. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  90. data/spec/dummy/config/locales/en.yml +5 -0
  91. data/spec/dummy/config/routes.rb +9 -0
  92. data/spec/dummy/db/development.sqlite3 +0 -0
  93. data/spec/dummy/db/migrate/2013032210540_users.rb +49 -0
  94. data/spec/dummy/db/migrate/20130326093048_msg_data.msg.rb +55 -0
  95. data/spec/dummy/db/schema.rb +96 -0
  96. data/spec/dummy/db/test.sqlite3 +0 -0
  97. data/spec/dummy/log/development.log +143 -0
  98. data/spec/dummy/log/test.log +1022 -0
  99. data/spec/dummy/public/404.html +26 -0
  100. data/spec/dummy/public/422.html +26 -0
  101. data/spec/dummy/public/500.html +25 -0
  102. data/spec/dummy/public/favicon.ico +0 -0
  103. data/spec/dummy/script/rails +6 -0
  104. data/spec/factories/msg/bounces.rb +9 -0
  105. data/spec/factories/msg/envelopes.rb +10 -0
  106. data/spec/factories/msg/messages.rb +10 -0
  107. data/spec/factories/msg/sendings.rb +7 -0
  108. data/spec/factories/users.rb +11 -0
  109. data/spec/helpers/msg/msg_helper_spec.rb +17 -0
  110. data/spec/lib/msg_spec.rb +15 -0
  111. data/spec/mailers/msg/devise_mailer_spec.rb +21 -0
  112. data/spec/mailers/msg/msg_mailer_spec.rb +36 -0
  113. data/spec/models/msg/bounce_spec.rb +19 -0
  114. data/spec/models/msg/envelope_spec.rb +62 -0
  115. data/spec/models/msg/message_spec.rb +19 -0
  116. data/spec/models/msg/sending_spec.rb +10 -0
  117. data/spec/routing/sendings_routing_spec.rb +31 -0
  118. data/spec/spec_helper.rb +70 -0
  119. metadata +446 -0
@@ -0,0 +1,54 @@
1
+ module Msg
2
+ class Sending < ActiveRecord::Base
3
+ attr_accessible :message_id, :envelopes_attributes
4
+
5
+ belongs_to :message
6
+ belongs_to :created_by, :class_name => Msg.user_class
7
+ has_many :envelopes, :dependent => :destroy
8
+
9
+ def receivers=(receivers)
10
+ receivers.each do |rec|
11
+ self.envelopes.build(:receiver => rec, :sending => self)
12
+ end
13
+ end
14
+
15
+ def statistics
16
+ sent = envelopes.count || 0
17
+ bounced = envelopes.bounced.count || 0
18
+ read = envelopes.opened.count || 0
19
+ unread = sent-read-bounced
20
+ [unread, read, bounced]
21
+ end
22
+
23
+ def self.add_receiver_hooks(klass, options)
24
+ key = klass.to_s.underscore
25
+
26
+ define_method :"#{key}_group" do
27
+ self.receiving_group if self.receiving_class == key
28
+ end
29
+
30
+ # class_group= is called from the SendingsController and given the _name_ of a messaging group,
31
+ # we get the designated proc from the class messaging rules, then call it to get an array of receivers
32
+ #
33
+ define_method :"#{key}_group=" do |name|
34
+ self.receiving_class = key
35
+ self.receiving_group = name
36
+ self.receivers = klass.messaging_groups[name.to_sym].call unless name == 'selected'
37
+ end
38
+ attr_accessible :"#{key}_group"
39
+
40
+ define_method :"#{key}_receiver_ids" do
41
+ self.envelopes.map(&:receiver_id) if self.receiving_class == key
42
+ end
43
+ attr_accessible :"#{key}_receiver_ids"
44
+
45
+ # class_receiver_ids= is called from the SendingsController and given a list of receiver ids of this class.
46
+ # they are instantiated and passed to receivers=
47
+ #
48
+ define_method :"#{key}_receiver_ids=" do |ids|
49
+ self.receivers = klass.find(ids)
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ !!!
2
+ %html{:lang => 'en'}
3
+ %head
4
+ %title
5
+ - if content_for?(:pagetitle)
6
+ = yield :pagetitle
7
+ \|
8
+ = t(:msg)
9
+
10
+ = stylesheet_link_tag "msg"
11
+ = javascript_include_tag "msg"
12
+ = content_for :head
13
+ = csrf_meta_tags
14
+
15
+ %body
16
+ #header
17
+ %p.warning
18
+ = t :please_set_layout
19
+
20
+ #page
21
+ #content
22
+ = yield
23
+ #margin
24
+ = content_for :margin
25
+
26
+ #flashes
27
+ %p.notice= notice
28
+ %p.alert= alert
29
+
30
+ #mask
@@ -0,0 +1,10 @@
1
+ !!!
2
+ %html{:lang => 'en'}
3
+ %head
4
+ %title
5
+ = @subject
6
+
7
+ %body
8
+ #content
9
+ = yield
10
+
@@ -0,0 +1,5 @@
1
+ - bounce ||= listing
2
+
3
+ %li.bounce
4
+ = bounce.envelope.to_address
5
+ = l(bounce.created_at, :format => :natural_with_date)
@@ -0,0 +1,10 @@
1
+ - bounces ||= @bounces || Msg::Bounce.order('created_at DESC').limit(5)
2
+
3
+ #bouncebox{:data => {:refreshable => true, :url => msg.bounces_path(:format => :js)}}
4
+ - if bounces.any?
5
+ %h3
6
+ = link_to t(:bounce_report), msg.bounces_url
7
+
8
+ %ul.bounces
9
+ = render :partial => "msg/bounces/listing", :collection => bounces
10
+
@@ -0,0 +1,5 @@
1
+ #bounces
2
+ = render :partial => "msg/bounces/bounce", :collection => @bounces
3
+
4
+ -content_for :title do
5
+ = t :bounces
@@ -0,0 +1 @@
1
+ = sanitize(@contents.html_safe, :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
@@ -0,0 +1 @@
1
+ = sanitize(@contents.html_safe, :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
@@ -0,0 +1,5 @@
1
+ - envelope ||= listing
2
+
3
+ %li{:class => "envelope #{envelope.status}"}
4
+ = envelope.receiver.name
5
+
@@ -0,0 +1,10 @@
1
+ - if editable?(message)
2
+ .menu{:data => {:for => "message_#{message.id}"}}
3
+ %ul.actions
4
+ %li
5
+ = link_to t(:edit_message), msg.edit_message_url(message), :class => 'edit', :data => {:action => "popup", :affected => "#message_#{message.id}, #sentbox", :group => "messages"}
6
+ %li
7
+ = link_to t(:preview_and_send), msg.message_url(message), :class => "edit", :data => {:action => "popup", :affected => "#sentbox", :group => "messages"}
8
+ - unless message.transactional?
9
+ %li
10
+ = link_to t(:delete_message), msg.message_url(message), :method => 'delete', :class => 'delete', :data => {:action => "remove", :removed => "#message_#{message.id}", :confirm => t(:confirm_delete_message, :subject => message.subject)}
@@ -0,0 +1,38 @@
1
+ = form_for @message, :html => {:class => 'edit message', :remote => true, :data => {:type => :html}} do |f|
2
+ %p.subject
3
+ = f.text_field :subject, :class => 'name', :placeholder => t(:message_subject)
4
+
5
+ %p.sender.messagedetail
6
+ = f.text_field :from_name, :class => 'from_name', :placeholder => t(:from) + ": " + Msg.default_from_name
7
+ = f.text_field :from_address, :class => 'from_address', :placeholder => Msg.default_from_address
8
+
9
+ %p.function.messagedetail
10
+ %span.transactional_detail
11
+ = f.text_field :function, :class => "function", :placeholder => t(:message_function)
12
+ = f.check_box :transactional, :data => {:action => "reveal", :affected => ".transactional_detail", :converse => ".saved"}
13
+ = f.label :transactional, t(:transactional_message)
14
+ %span.formnote
15
+ = t :transactional_message_note
16
+
17
+ .messagebody.wysihtml#e1
18
+ %p.show_details
19
+ = link_to t(:more_detail), "#", :class => "expander", :data => {:action => "toggle", :affected => ".messagedetail"}
20
+
21
+ = render "msg/messages/instructions"
22
+ .toolbar#t1
23
+ = render 'msg/shared/toolbar'
24
+ = f.text_area :body, :id => 'd1', :class => "body"
25
+
26
+ %p.saved
27
+ = f.check_box :saved, :data => {:action => "reveal", :affected => ".saved_detail"}
28
+ = f.label :saved, t(:save_for_reuse)
29
+ %span.formnote
30
+ = t :saved_note
31
+ %span.saved_detail
32
+ = f.text_field :description, :class => "description", :placeholder => t(:message_description)
33
+
34
+ .buttons
35
+ = f.submit t(:save_and_preview)
36
+ = t :or
37
+ = link_to t(:cancel), "/", :class => 'cancel'
38
+
@@ -0,0 +1,28 @@
1
+ .instructions
2
+ %p
3
+ Use double braces to insert these computed values into each message:
4
+ %ul
5
+ %li
6
+ %strong
7
+ {{formal_name}}
8
+ the recipient's full name and title
9
+ %li
10
+ %strong
11
+ {{informal_name}}
12
+ forename, if we know it, or full name without title
13
+ %li
14
+ %strong
15
+ {{email}}
16
+ the receiving email address
17
+ %li
18
+ %strong
19
+ {{sign_in_url}}
20
+ the address of the login page
21
+ %li
22
+ %strong
23
+ {{confirmation_url}}
24
+ a confirmation address for use in invitations
25
+ %li
26
+ %strong
27
+ {{password_reset_url}}
28
+ a reset address for use in reminder messages
@@ -0,0 +1,11 @@
1
+ - message ||= @message
2
+
3
+ .message{:id => "message_#{message.id}", :data => {:refreshable => true, :url => message_path(message, :format => :js)} }
4
+ %h2.name
5
+ = link_to shorten(message.subject, 54), msg.message_url(message), :class => "message", :data => {:action => "popup", :affected => "#sentbox", :group => "messages"}
6
+ = action_menulink(message)
7
+ = action_menu(message)
8
+ %p.description
9
+ = message.description
10
+ %p.excerpt
11
+ = shorten(message.body, 128)
@@ -0,0 +1,2 @@
1
+ #saved_messages.message_list{:data => {:refreshable => true, :url => msg.saved_messages_path(:format => :js)}}
2
+ = render :partial => "msg/messages/message", :collection => @saved_messages
@@ -0,0 +1,3 @@
1
+ #transactional_messages.message_list{:data => {:refreshable => true, :url => msg.transactional_messages_path(:format => :js)}}
2
+ = render :partial => "msg/messages/message", :collection => @transactional_messages
3
+
@@ -0,0 +1,7 @@
1
+ #message
2
+ .header
3
+ = link_to "X", '#', :class => "closer", :data => {:action => "close"}
4
+ %h2
5
+ = t :edit_message
6
+
7
+ = render :partial => 'form'
@@ -0,0 +1,23 @@
1
+ #messages
2
+
3
+ %p.action
4
+ = link_to t(:create_message), msg.new_message_url, :class => "add", :data => {:action => "popup", :affected => "#saved_messages"}
5
+
6
+ %h2.section
7
+ = t :transactional_messages
8
+
9
+ = render "msg/messages/transactional_messages"
10
+
11
+ %h2.section
12
+ = t :saved_messages
13
+ %span.action
14
+ = link_to t(:create_message), msg.new_message_url, :class => "add minimal", :data => {:action => "popup", :affected => "#saved_messages"}
15
+ = render "msg/messages/saved_messages"
16
+
17
+
18
+ -content_for :margin do
19
+ = render :partial => "msg/bounces/report"
20
+ = render :partial => "msg/sendings/report"
21
+
22
+ -content_for :title do
23
+ = t :messages
@@ -0,0 +1,7 @@
1
+ #message
2
+ .header
3
+ = link_to "X", '#', :class => "closer", :data => {:action => "close"}
4
+ %h2
5
+ = t :add_message
6
+
7
+ = render :partial => 'form'
@@ -0,0 +1,4 @@
1
+ - message ||= @message
2
+ - receiver ||= @receiver
3
+
4
+ = sanitize(message.render_for(receiver), :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
@@ -0,0 +1,25 @@
1
+ #preview_message
2
+ .header
3
+ = link_to "X", '#', :class => "closer", :data => {:action => "close"}
4
+ %h2
5
+ = t :preview_message
6
+ .headers
7
+ %p
8
+ %span.field
9
+ = t(:subject).titlecase + ":"
10
+ %strong
11
+ = @message.subject
12
+ %p
13
+ %span.field
14
+ = t(:to).titlecase + ":"
15
+ %strong
16
+ = @receiver.email
17
+ %p
18
+ %span.field
19
+ = t(:from).titlecase + ":"
20
+ %strong
21
+ = @message.from
22
+
23
+ - sending = @message.sendings.build
24
+ = render :partial => "msg/sendings/form", :locals => {:sending => sending}
25
+
@@ -0,0 +1,2 @@
1
+ = sanitize(@contents.html_safe, :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
2
+ %img{:src => msg.envelope_url(@envelope)}
@@ -0,0 +1,45 @@
1
+ - sending ||= @sending
2
+ - message ||= @message
3
+ - receiver ||= @receiver
4
+ - klasses = Msg.receiving_classes
5
+
6
+ = form_for [message, sending], :as => :sending do |f|
7
+
8
+ .receivers
9
+ - klasses.each do |klass|
10
+ - key = klass.underscore
11
+
12
+ %h3
13
+ = t(:send_to)
14
+ = t("msg.#{key}") unless klasses.length == 1
15
+
16
+ %ul.choose_group
17
+ - klass.constantize.messaging_groups.each_pair do |name, proc|
18
+ - count = proc.call.count
19
+ %li.group
20
+ = f.radio_button "#{key}_group", name, :data => {:action => "reveal", :converse => "ul.choose_receivers"}, :disabled => count == 0
21
+ %label{:for => "sending_#{key}_group_#{name}"}
22
+ = t("msg.groups.#{name}")
23
+ %span.note
24
+ = t(:receiver_count, :count => count)
25
+
26
+ %li.group
27
+ = f.radio_button "#{key}_group", :selected, :data => {:action => "reveal", :affected => "ul.choose_receivers"}
28
+ %label{:for => "sending_#{key}_group_selected"}
29
+ = t("msg.groups.selected")
30
+
31
+ %ul.choose_receivers
32
+ - klass.constantize.order('name ASC').each do |rec|
33
+ %li.receiver
34
+ = check_box_tag "sending[#{key}_receiver_ids][]", rec.id, false, :id => "sending_#{key}_receiver_ids_#{rec.id}"
35
+ %label{:for => "sending_#{key}_receiver_ids_#{rec.id}"}
36
+ = rec.name
37
+
38
+ // #todo: update the preview on selection, and add a control to page through the selected group of people
39
+ %iframe.body{:src => msg.preview_message_url(message, :receiver_type => receiver.class.to_s.downcase.underscore.to_s, :receiver_id => receiver.id)}
40
+
41
+ .buttons
42
+ = f.submit t(:send_message)
43
+ = t :or
44
+ = link_to t(:close), "/", :class => 'cancel'
45
+
@@ -0,0 +1,17 @@
1
+ - sending ||= listing
2
+ - receiver_count = sending.envelopes.count
3
+
4
+ %li.sending
5
+ %a{:href => msg.sending_url(sending)}
6
+ %span.pie{:data => {:diameter => 16}}<
7
+ = sending.statistics.join(',')
8
+ = shorten(sending.message.subject, 36)
9
+ - if sending.receiving_group
10
+ = t(:sent_to)
11
+ = t("msg.groups.#{sending.receiving_group}")
12
+ = t(:receiver_count, :count => sending.envelopes.count)
13
+
14
+ - else
15
+ = t(:sent_to_count, :count => sending.envelopes.count)
16
+ = t(:at)
17
+ = l(sending.created_at, :format => :natural_with_date)
@@ -0,0 +1,8 @@
1
+ - sendings ||= @sendings || Msg::Sending.order('created_at DESC').limit(5)
2
+
3
+ #sentbox{:data => {:refreshable => true, :url => msg.sendings_path(:format => :js, :show => 5)}}
4
+ %h3
5
+ = link_to t(:sent_report), msg.sendings_url
6
+
7
+ %ul.sendings
8
+ = render :partial => "msg/sendings/listing", :collection => sendings
@@ -0,0 +1,22 @@
1
+ - sending ||= @sending
2
+
3
+ .sending{:id => "sending_#{sending.id}", :data => {:refreshable => true, :url => sending_path(sending, :format => :js)} }
4
+ %h2.name
5
+ %span.pie{:data => {:diameter => 20}}<
6
+ = sending.statistics.join(',')
7
+ = link_to shorten(sending.message.subject, 54), msg.sending_url(sending)
8
+
9
+ %p.description
10
+ - if sending.receiving_group
11
+ = t(:sent_to)
12
+ = t("msg.groups.#{sending.receiving_group}")
13
+ = t(:receiver_count, :count => sending.envelopes.count)
14
+ - else
15
+ = t(:sent)
16
+ = t(:at)
17
+ = l(sending.created_at, :format => :natural_with_date)
18
+
19
+ %p.responses
20
+ = t(:sent_count, :count => sending.envelopes.count) + '.'
21
+ = t(:opened_count, :count => sending.envelopes.opened.count) + '.'
22
+ = t(:bounced_count, :count => sending.envelopes.bounced.count) + '.'
@@ -0,0 +1,2 @@
1
+ .sending_list{:data => {:refreshable => true, :url => msg.sendings_path(:format => :js)}}
2
+ = render :partial => "msg/sendings/sending", :collection => @sendings
@@ -0,0 +1,8 @@
1
+ #sent_messages
2
+ = render "msg/sendings/sendings"
3
+
4
+ -content_for :title do
5
+ = t :sent_messages
6
+
7
+ -content_for :margin do
8
+ = render :partial => "msg/bounces/report"
@@ -0,0 +1,9 @@
1
+ #send_message
2
+ .header
3
+ = link_to "X", '#', :class => "closer", :data => {:action => "close"}
4
+ %h2
5
+ = t(:send_the_message)
6
+ %strong
7
+ = @message.subject
8
+
9
+ = render :partial => 'form'
@@ -0,0 +1,2 @@
1
+ - if @sending.envelopes.any?
2
+ = sanitize(@sending.envelopes.first.contents.html_safe , :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)