Skip to content

Commit

Permalink
Wheels::Mailer enhancements/optimizations for use in a mail queue.
Browse files Browse the repository at this point in the history
  • Loading branch information
bernerdschaefer committed Feb 20, 2009
1 parent 7e9daff commit d7f68e6
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
85 changes: 85 additions & 0 deletions lib/wheels/mailer.rb
@@ -1,3 +1,4 @@
require "cgi"
require "mailfactory"

require Pathname(__FILE__).dirname + "mail_servers/abstract"
Expand All @@ -9,6 +10,90 @@ class Mailer < MailFactory

attr_accessor :mail_server

##
# MailFactory by default generates the attachment and body boundaries
# on initialize, which is rather slow when you're creating a lot of
# mailer objects in a loop.
#
# This patch offloads the cost of generating the boundaries to the construct
# method (which is called by to_s()), so this more expensive operation
# can occure on the mail server side.
#
def initialize
@headers = Array.new()
@attachments = Array.new()
@html = nil
@text = nil
@charset = 'utf-8'
end

def construct(*args)
@attachmentboundary ||= generate_boundary()
@bodyboundary ||= generate_boundary()
super
end

def envelope_id
@envelope_id ||= `uuidgen`.chomp
end

##
# For displaying emails in an interface, we want to store the
# subject before it has been encoded for delivery.
#
def subject=(subject)
@subject = subject
super
end

def subject
@subject
end

##
# We ensure that the envelope id for this message gets set when the message
# is contructed. We remove any existing Mail-From headers.
#
def headers_to_s
remove_header("Mail-From")
@headers.unshift("Mail-From: #{`whoami`.chomp}@#{`hostname`.chomp} ENVID=#{envelope_id}")
super
end

##
# We want to automatically assign the value of @mailer to self whenever
# a view is passed to the mailer object. This lets us use, for instance,
# the envelope_id to track click-through's and bounces using the same
# identifier.
#
%w(html= rawhtml= text=).each do |method|
define_method(method) do |value|
if value.is_a?(Wheels::View)
value.context.merge(:mailer => self)
end
super
end
end

def text
@text
end

def html
@html
end

def tokenize_urls!(mail_server_url)
[:@html, :@text].each do |ivar|
if content = instance_variable_get(ivar)
new_content = content.gsub(/(http(s)?:\/\/.+?)(?=[" ]|$)/) do |url|
"#{mail_server_url}/m/#{envelope_id}?r=#{CGI.escape([url].pack("m"))}"
end
instance_variable_set(ivar, new_content)
end
end
end

def send!
mail_server.deliver(self)
end
Expand Down
1 change: 1 addition & 0 deletions spec/mailer_spec.rb
Expand Up @@ -19,4 +19,5 @@ def deliver(mail)
mail.mail_server = @server
mail.send!.should == mail
end

end
45 changes: 45 additions & 0 deletions test/helper.rb
@@ -0,0 +1,45 @@
require "rubygems"
require "test/unit"
require Pathname(__FILE__).dirname.parent + "lib/wheels"
require "wheels/xml_view"

module Rack
class Request
def params
@params ||= {}
end
end
end

def upload(filename)
input = <<-EOF
--AaB03x\r
Content-Disposition: form-data; name="file"; filename="#{filename}"\r
Content-Type: image/jpeg\r
\r
#{File.read(Pathname(__FILE__).dirname + "samples" + filename)}\r
\r
--AaB03x\r
Content-Disposition: form-data; name="video[caption]"\r
\r
test\r
--AaB03x\r
Content-Disposition: form-data; name="video[transcoder][1]"\r
\r
on\r
--AaB03x\r
Content-Disposition: form-data; name="video[transcoder][4]"\r
\r
on\r
--AaB03x\r
Content-Disposition: form-data; name="video[transcoder][5]"\r
\r
on\r
--AaB03x--\r
\r
EOF
Rack::Request.new Rack::MockRequest.env_for("/",
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
"CONTENT_LENGTH" => input.size,
:input => input)
end
33 changes: 33 additions & 0 deletions test/mailer_test.rb
@@ -0,0 +1,33 @@
require "helper"
require "wheels/mailer"

class MailerTest < Test::Unit::TestCase

def test_tokenize_urls_with_plain_text
mailer = Wheels::Mailer.new
url = "http://test.com"
mailer.text = url
mailer.tokenize_urls!("http://m.wieck.com")

assert_equal("http://m.wieck.com/m/#{mailer.envelope_id}?r=#{CGI.escape([url].pack("m"))}", mailer.text)
end

def test_tokenize_urls_with_html
mailer = Wheels::Mailer.new
url = "http://test.com"
mailer.rawhtml = "<a href=\"#{url}\">Link</a>"
mailer.tokenize_urls!("http://m.wieck.com")

assert_equal("<a href=\"http://m.wieck.com/m/#{mailer.envelope_id}?r=#{CGI.escape([url].pack("m"))}\">Link</a>", mailer.html)
end

def test_tokenize_urls_with_https
mailer = Wheels::Mailer.new
url = "https://test.com"
mailer.text = url
mailer.tokenize_urls!("http://m.wieck.com")

assert_equal("http://m.wieck.com/m/#{mailer.envelope_id}?r=#{CGI.escape([url].pack("m"))}", mailer.text)
end

end

0 comments on commit d7f68e6

Please sign in to comment.