Permalink
Browse files

Added html footers

  • Loading branch information...
aiwilliams committed Mar 26, 2010
1 parent f9725ad commit 8c64632ef673501aac669a411d36f6352a42034f
Showing with 257 additions and 165 deletions.
  1. +2 −1 README
  2. +64 −46 lib/mlist/mail_list.rb
  3. +56 −20 lib/mlist/util/email_helpers.rb
  4. +1 −3 lib/mlist/util/quoting.rb
  5. +36 −24 lib/mlist/util/tmail_methods.rb
  6. +98 −71 spec/models/mail_list_spec.rb
View
3 README
@@ -141,7 +141,7 @@ environment.rb after the initialize block (our gem needs to have been loaded):
# Please do specify a version, and check for the latest!
config.gem "mlist", :version => '0.1.0'
end
-
+
MLIST_SERVER = MList::Server.new(
:list_manager => MList::Manager::Database.new,
:email_server => MList::EmailServer::Default.new(
@@ -185,6 +185,7 @@ list something like this:
(The MIT License)
Copyright (c) 2008-2009 Adam Williams (aiwilliams)
+Portions from Rails are Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the 'Software'), to deal in the
View
@@ -1,7 +1,7 @@
module MList
class MailList < ActiveRecord::Base
set_table_name 'mlist_mail_lists'
-
+
# Provides the MailList for a given implementation of MList::List,
# connecting it to the provided email server for delivering posts.
#
@@ -17,19 +17,19 @@ def self.find_or_create_by_list(list, outgoing_server)
mail_list.outgoing_server = outgoing_server
mail_list
end
-
+
include MList::Util::EmailHelpers
-
+
belongs_to :manager_list, :polymorphic => true
-
+
before_destroy :delete_unreferenced_email
has_many :messages, :class_name => 'MList::Message', :dependent => :delete_all
has_many :threads, :class_name => 'MList::Thread', :dependent => :delete_all
-
+
delegate :address, :label, :post_url, :to => :list
-
+
attr_accessor :outgoing_server
-
+
# Creates a new MList::Message and delivers it to the subscribers of this
# list.
#
@@ -45,7 +45,7 @@ def post(email_or_attributes)
:email => MList::Email.new(:source => email.to_s)
), :search_parent => false, :copy_sender => email.copy_sender
end
-
+
# Processes the email received by the MList::Server.
#
def process_email(email, subscriber)
@@ -57,7 +57,7 @@ def process_email(email, subscriber)
:email => email
), :copy_sender => list.copy_sender?(subscriber)
end
-
+
# Answers the provided subject with superfluous 're:' and this list's
# labels removed.
#
@@ -72,36 +72,36 @@ def clean_subject(string)
without_label
end
end
-
+
def find_parent_message(email)
if in_reply_to = email.header_string('in-reply-to')
message = messages.find(:first,
:conditions => ['identifier = ?', remove_brackets(in_reply_to)])
return message if message
end
-
+
if email.references
reference_identifiers = email.references.collect {|rid| remove_brackets(rid)}
message = messages.find(:first,
:conditions => ['identifier in (?)', reference_identifiers],
:order => 'created_at desc')
return message if message
end
-
+
if email.subject =~ REGARD_RE
message = messages.find(:first,
:conditions => ['subject = ?', remove_regard(clean_subject(email.subject))],
:order => 'created_at asc')
return message if message
end
end
-
+
# The MList::List instance of the list manager.
#
def list
@list ||= manager_list
end
-
+
def manager_list_with_dual_type=(list)
if list.is_a?(ActiveRecord::Base)
self.manager_list_without_dual_type = list
@@ -112,27 +112,27 @@ def manager_list_with_dual_type=(list)
end
end
alias_method_chain :manager_list=, :dual_type
-
+
# Distinct footer start marker. It is important to realize that changing
# this could be problematic.
#
FOOTER_BLOCK_START = "-~----~~----~----~----~----~---~~-~----~------~--~-~-"
-
+
# Distinct footer end marker. It is important to realize that changing
# this could be problematic.
#
FOOTER_BLOCK_END = "--~--~---~-----~--~----~-----~~~----~---~---~--~----~"
-
+
private
FOOTER_BLOCK_START_RE = %r[#{FOOTER_BLOCK_START}]
FOOTER_BLOCK_END_RE = %r[#{FOOTER_BLOCK_END}]
-
+
# http://mail.python.org/pipermail/mailman-developers/2006-April/018718.html
def bounce_headers
# tmail would not correctly quote the label in the sender header, which would break smtp delivery
{'sender' => "<mlist-#{address}>", 'errors-to' => "#{label} <mlist-#{address}>"}
end
-
+
def delete_unreferenced_email
conditions = %Q{
mlist_emails.id in (
@@ -144,7 +144,7 @@ def delete_unreferenced_email
)}
MList::Email.delete_all(conditions)
end
-
+
def strip_list_footers(content)
if content =~ FOOTER_BLOCK_START_RE
in_footer_block = false
@@ -160,7 +160,7 @@ def strip_list_footers(content)
end
content
end
-
+
# http://www.jamesshuggins.com/h/web1/list-email-headers.htm
def list_headers
headers = list.list_headers.dup
@@ -169,51 +169,51 @@ def list_headers
headers.update(bounce_headers)
headers.delete_if {|k,v| v.nil?}
end
-
+
# Answer headers values which should be stripped from outgoing email.
#
def strip_headers
%w(return-receipt-to domainkey-signature dkim-signature)
end
-
+
def process_message(message, options = {})
raise MList::DoubleDeliveryError.new(message) unless message.new_record?
-
+
options = {
:search_parent => true,
:delivery_time => Time.now,
:copy_sender => false
}.merge(options)
-
+
transaction do
thread = find_thread(message, options)
thread.updated_at = options[:delivery_time]
-
+
delivery = prepare_delivery(message, options)
thread.messages << message
-
+
self.updated_at = options[:delivery_time]
thread.save! && save!
-
+
outgoing_server.deliver(delivery.tmail)
end
-
+
message
end
-
+
def prepare_delivery(message, options)
message.identifier = outgoing_server.generate_message_id
message.created_at = options[:delivery_time]
message.subject = clean_subject(message.subject)
-
+
recipient_addresses = message.recipient_addresses
sender_address = message.subscriber.email_address
if options[:copy_sender]
recipient_addresses << sender_address unless recipient_addresses.include?(sender_address)
else
recipient_addresses.delete(sender_address)
end
-
+
returning(message.delivery) do |delivery|
delivery.date ||= options[:delivery_time]
delivery.message_id = message.identifier
@@ -228,22 +228,40 @@ def prepare_delivery(message, options)
prepare_list_footer(delivery, message)
end
end
-
+
def prepare_list_footer(delivery, message)
- text_plain_part = delivery.text_plain_part
- return unless text_plain_part
-
- content = strip_list_footers(text_plain_part.body)
+ footer = list_footer(message)
+ prepare_html_footer(delivery.text_html_part, footer)
+ prepare_text_footer(delivery.text_plain_part, footer)
+ end
+
+ def prepare_html_footer(part, footer)
+ return unless part
+ content = part.body
+ content.gsub!(%r(<p>\s*#{FOOTER_BLOCK_START_RE}.*?#{FOOTER_BLOCK_END_RE}\s*<\/p>)im, '')
+ content.strip!
+ html_footer = "<p>#{auto_link_urls(text_to_html(footer))}</p>"
+
+ unless content.sub!(/<\/body>/, "#{html_footer}</body>")
+ # no body was there, substitution failed
+ content << html_footer
+ end
+ part.body = content
+ end
+
+ def prepare_text_footer(part, footer)
+ return unless part
+ content = strip_list_footers(part.body)
content << "\n\n" unless content.end_with?("\n\n")
- content << list_footer(message)
- text_plain_part.body = content
+ content << footer
+ part.body = content
end
-
+
def list_footer(message)
content = list.footer_content(message)
"#{FOOTER_BLOCK_START}\n#{content}\n#{FOOTER_BLOCK_END}"
end
-
+
def list_subject(string)
list_subject = string.dup
if list_subject =~ REGARD_RE
@@ -252,26 +270,26 @@ def list_subject(string)
"#{subject_prefix} #{list_subject}"
end
end
-
+
def find_thread(message, options)
message.parent = find_parent_message(message.email) if message.email && options[:search_parent]
message.parent ? message.parent.thread : threads.build
end
-
+
def reply_to_header(message)
if list.reply_to_list?
"#{label} #{bracket(address)}"
else
subscriber_name_and_address(message.subscriber)
end
end
-
+
def subject_prefix_regex
@subject_prefix_regex ||= Regexp.new(Regexp.escape(subject_prefix) + ' ')
end
-
+
def subject_prefix
@subject_prefix ||= "[#{label}]"
end
end
-end
+end
Oops, something went wrong.

0 comments on commit 8c64632

Please sign in to comment.