<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Flvorful Bloggage: Tag part4</title>
    <link>http://blog.flvorful.com/articles/tag/part4</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Deep in Rails: ActionMailer#deliver Part VI</title>
      <description>&lt;p&gt;So now we know how Rails sends emails.  What can we do with that knowledge?&lt;/p&gt;

&lt;p&gt;All kinds of stuff.&lt;/p&gt;

&lt;p&gt;One of my clients needed the ability to send messages through 3 different &lt;span class="caps"&gt;SMTP&lt;/span&gt; servers.  They wanted it to be easy to use for their developers and allow them to change out &lt;span class="caps"&gt;SMTP&lt;/span&gt; servers for each mailer method.  Now that we know how AM does it&#8217;s thing, we can use that knowledge to create a quick patch and solve the above problem.&lt;/p&gt;

&lt;p&gt;We&#8217;ll create a new file in out Rails app inside lib/ and call it &lt;code&gt;action_mailer_hacks.rb&lt;/code&gt;.  Inside of the file add the following (dont worry, we&#8217;ll go over each line)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module ActionMailerHacks

    module InstanceMethods
        def deliver_with_switchable_smtp!(mail = @mail)
            unless logger.nil?
                logger.info  "Switching SMTP server to: #{new_smtp.inspect}" 
            end
            ActionMailer::Base.smtp_settings = new_smtp unless new_smtp.nil?
            deliver_without_switchable_smtp!(mail = @mail)
        end

    end

    def self.included(receiver)
        receiver.send :include, InstanceMethods
        receiver.class_eval do
            adv_attr_accessor :new_smtp
            alias_method_chain :deliver!, :switchable_smtp
        end
    end
end

ActionMailer::Base.send :include, ActionMailerHacks
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First, in &lt;code&gt;module InstanceMethods&lt;/code&gt;, we create a new deliver method that will switch the &lt;span class="caps"&gt;SMTP&lt;/span&gt; server from AM.  We do some quick logging and then set &lt;code&gt;AM::Base.smtp_settings&lt;/code&gt; to the new smtp server.  After we do that, we call &lt;code&gt;deliver_without_switchable_smtp&lt;/code&gt; which gets created when we do our &lt;em&gt;alias_method_chaining&lt;/em&gt; later down the page.&lt;/p&gt;

&lt;p&gt;When this module is included we include the &lt;code&gt;InstanceMethods&lt;/code&gt; module into the receiver and then run &lt;code&gt;class_eval&lt;/code&gt; so that we can create a new &lt;code&gt;adv_attr_accessor&lt;/code&gt; called &lt;code&gt;new_smtp&lt;/code&gt; and then call &lt;code&gt;alias_method_chain&lt;/code&gt; to create our &lt;code&gt;without&lt;/code&gt; method.  After that we include this whole module into AM::Base and we&#8217;re done with the hack.  Add &lt;code&gt;require "action_mailer_hacks.rb"&lt;/code&gt; to your &lt;code&gt;environment.rb&lt;/code&gt; file and we&#8217;re ready for the mailer.&lt;/p&gt;

&lt;p&gt;Now we move on to MessageMailer and actually use the hack.&lt;/p&gt;

&lt;pre id="scroll_to_here" &gt;&lt;code&gt;class MessageMailer &amp;lt; ActionMailer::Base
  def contact_form(msg_from, message)
    subject    'Im contacting you'
    recipients "someemail@somedomain.com" 
        new_smtp   :address =&amp;gt; 'mail.someplace.com', :port =&amp;gt; 25, :domain =&amp;gt; 'someplace.com', :authentication =&amp;gt; :login, :user_name =&amp;gt; 'xxxxdddd', :password =&amp;gt; 'secret'
    from       msg_from
    sent_on    Time.now
    body       :message =&amp;gt; message
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All we do is call &lt;code&gt;new_smtp&lt;/code&gt; with our new server address and then this method gets delivered through that &lt;span class="caps"&gt;SMTP&lt;/span&gt; server.  That&#8217;s it.  Simple and clean, exactly how I like it.&lt;/p&gt;

&lt;p&gt;Well, that was fun.  Next time, we&#8217;ll look through something a little shorter, maybe migrations.  Until then, have fun and keep codin&#8217;&lt;/p&gt;</description>
      <pubDate>Sun, 20 Dec 2009 09:41:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:f0e64747-3896-444c-b2ae-d02320362aa1</guid>
      <author>jake</author>
      <link>http://blog.flvorful.com/articles/2009/12/20/deep-in-rails-actionmailer-deliver-part-vi</link>
      <category>Rails</category>
      <category>rails</category>
      <category>action_mailer</category>
      <category>deep</category>
      <category>DIR</category>
      <category>part4</category>
    </item>
    <item>
      <title>Deep in Rails: ActionMailer#deliver Part V</title>
      <description>&lt;p&gt;So now we have our mail object.  Let&amp;#8217;s send it. &lt;/p&gt;

&lt;p&gt;For the sending of the message, we need to go back to the beginning, &lt;code&gt;method_missing&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 62 action_mailer/base.rb)
def method_missing(method_symbol, *parameters) #:nodoc:
  if match = matches_dynamic_method?(method_symbol)

    case match[1]
      when 'create'  then new(match[2], *parameters).mail
      when 'deliver' then new(match[2], *parameters).deliver!
      when 'new'     then nil
      else super
    end
  else
    super
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You remember &lt;code&gt;method_missing&lt;/code&gt; from a long time ago.  We just finished the first part of the line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;when 'deliver' then new(match[2], *parameters).deliver!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We created the new AM object and now we call &lt;code&gt;deliver!&lt;/code&gt; on it.  That&amp;#8217;s our next stop:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 520 action_mailer/base.rb)
def deliver!(mail = @mail)
  raise "no mail object available for delivery!" unless mail
  unless logger.nil?
    logger.info  "Sent mail to #{Array(recipients).join(', ')}"
    logger.debug "\n#{mail.encoded}"
  end

  begin
    __send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
  rescue Exception =&amp;gt; e  # Net::SMTP errors or sendmail pipe errors
    raise e if raise_delivery_errors
  end

  return mail
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The beginning of this method does some checking and logging.  The main part of this method is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We are again using &lt;code&gt;__send__&lt;/code&gt; to bypass any possible overridden method and calling &lt;code&gt;perform_delivery_#{delivery_method}&lt;/code&gt; with the mail object.  &lt;code&gt;delivery_method&lt;/code&gt; is a configuration attribute on the AM class along with &lt;code&gt;perform_deliveries&lt;/code&gt;.  AM defaults to &amp;#8220;smtp&amp;#8221; for &lt;code&gt;delivery_method&lt;/code&gt; and &amp;#8220;true&amp;#8221; for &lt;code&gt;perform_deliveries&lt;/code&gt; so the method we end up calling in our example is &lt;code&gt;perform_delivery_smtp&lt;/code&gt;.  Let&amp;#8217;s see that code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 680 action_mailer/base.rb)
def perform_delivery_smtp(mail)
  destinations = mail.destinations
  mail.ready_to_send
  sender = (mail['return-path'] &amp;amp;&amp;amp; mail['return-path'].spec) || mail.from

  smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
  smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] &amp;amp;&amp;amp; smtp.respond_to?(:enable_starttls_auto)
  smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
             smtp_settings[:authentication]) do |smtp|
    smtp.sendmail(mail.encoded, sender, destinations)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the finale.  The climax.  The whole reason we even engage in &lt;code&gt;ActionMailer&lt;/code&gt;, to actualy send an email.  Here we go.&lt;/p&gt;

&lt;p&gt;The first line pulls the &lt;code&gt;destinations&lt;/code&gt; (recipients) from the mail object and stores them in a variable.  Next, we call &lt;code&gt;ready_to_send&lt;/code&gt; on the mail object which is also the TMail object (remember that we assigned the final TMail object to the @mail attribute on our AM object).  This method is defined in &lt;code&gt;TMail::Net&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 62 action_mailer/tmail-1.2.3/tmail-1.2.3/net.rb)
def ready_to_send
  delete_no_send_fields
  add_message_id
  add_date
end

NOSEND_FIELDS = %w(
  received
  bcc
)

def delete_no_send_fields
  NOSEND_FIELDS.each do |nm|
    delete nm
  end
  delete_if {|n,v| v.empty? }
end

def add_message_id( fqdn = nil )
  self.message_id = ::TMail::new_message_id(fqdn)
end

def add_date
  self.date = Time.now
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, if you scan through that code you may notice that we are calling &lt;code&gt;delete&lt;/code&gt; and &lt;code&gt;delete_if&lt;/code&gt; like we were in a standard &lt;code&gt;Enumerable&lt;/code&gt; object, but we are not.  TMail also defines those methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def delete( key )
  @header.delete key.downcase
end

def delete_if
  @header.delete_if do |key,val|
    if Array === val
      val.delete_if {|v| yield key, v }
      val.empty?
    else
      yield key, val
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What we are doing with all this is stripping and setting some defaults.  &lt;code&gt;delete_no_send_fields&lt;/code&gt; get&amp;#8217;s rid of the &amp;#8220;received&amp;#8221; and &amp;#8220;bcc&amp;#8221; keys from our header and we are getting rid of any headers that have empty values.  After that we set a nice new hex type id for this email with &lt;code&gt;TMail.new_message_id&lt;/code&gt; which is defined in &lt;code&gt;TMail::Utils&lt;/code&gt; which gives us a string with a hex code attached to your machine&amp;#8217;s hostname.  The last line adds the date to the mail message and that&amp;#8217;s it.&lt;/p&gt;

&lt;p&gt;The next line sets the sender attribute.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sender = (mail['return-path'] &amp;amp;&amp;amp; mail['return-path'].spec) || mail.from
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we get into the actual sending of the email.  We aren&amp;#8217;t going to go into it because it is part of Ruby&amp;#8217;s core lib, but we will quickly skim over it to see what&amp;#8217;s going on:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] &amp;amp;&amp;amp; smtp.respond_to?(:enable_starttls_auto)
smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
           smtp_settings[:authentication]) do |smtp|
  smtp.sendmail(mail.encoded, sender, destinations)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First, we create the new SMTP object and then we enable StartTLS if necessary (this allows you to send email through SMTP hosts that require SSL connections).  Next we login to the SMTP server (with the &lt;code&gt;start&lt;/code&gt; command) and call &lt;code&gt;sendmail&lt;/code&gt; inside the block to do the actual delivery.  &lt;/p&gt;

&lt;p&gt;We&amp;#8217;re done.  That&amp;#8217;s how an email gets sent in Rails.  Next week we will create a quick monkey patch for ActionMailer based on the information that we learned from the trek.&lt;/p&gt;


</description>
      <pubDate>Mon, 14 Dec 2009 12:54:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:a6a6693d-ab06-4635-8b2c-fa3af2a3cffb</guid>
      <author>jake</author>
      <link>http://blog.flvorful.com/articles/2009/12/14/deep-in-rails-actionmailer-deliver-part-v</link>
      <category>Rails</category>
      <category>rails</category>
      <category>action_mailer</category>
      <category>deep</category>
      <category>DIR</category>
      <category>part4</category>
    </item>
    <item>
      <title>Deep in Rails: ActionMailer#deliver Part IV</title>
      <description>
&lt;p&gt;So we just opened up &lt;code&gt;CompiledTemplates&lt;/code&gt; and defined (or compiled) our unique method for this particular template.  Now we continue with &lt;code&gt;render&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
def render(view, local_assigns = {})
  compile(local_assigns)

  view.with_template self do
    view.send(:_evaluate_assigns_and_ivars)
    view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)

    view.send(method_name(local_assigns), local_assigns) do |*names|
      ivar = :@_proc_for_layout
      if !view.instance_variable_defined?(:"@content_for_#{names.first}") &amp;&amp; view.instance_variable_defined?(ivar) &amp;&amp; (proc = view.instance_variable_get(ivar))
        view.capture(*names, &amp;proc)
      elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
        view.instance_variable_get(ivar)
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and our params:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;view =&gt; #&lt;ActionView::Base:0x348189c 
          @template_format=:html, 
          @assigns={:message=&gt;"Send this message"}, 
          @helpers=#&lt;ActionView::Base::ProxyModule:0x3481810&gt;, 
          @controller=#&lt;MessageMailer:0x34904a0 
              @action_name="contact_form", 
              @subject="Im contacting you", 
              @content_type="text/plain", 
              @implicit_parts_order=["text/html", "text/enriched", "text/plain"], 
              @from="jake@somewhere.com", 
              @sent_on=Fri Nov 13 17:49:58 -0600 2009, 
              @headers={},
              @default_template_name="contact_form", 
              @mime_version="1.0", 
              @body={:message=&gt;"Send this message"}, 
              @mailer_name="message_mailer", 
              @recipients="someemail@somedomain.com", 
              @parts=[], 
              @template=#&lt;ActionView::Base:0x348189c ...&gt;, 
              @charset="utf-8"&gt;, 
          @_current_render=nil, 
          @assigns_added=nil, 
          @_first_render=nil, 
          @view_paths=["/example_app/app/views"]&gt;
local_assigns =&gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first thing we do after we compile our unique method is call &lt;code&gt;with_template&lt;/code&gt; on &lt;code&gt;view&lt;/code&gt; which is a convenient method that allows us to temporarily swap out the current template for the view, set it to another one, do some processing and then return the original template back to the view.  Let&#8217;s see &lt;code&gt;with_template&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 298 action_pack/action_view/base.rb)
def with_template(current_template)
  last_template, self.template = template, current_template
  yield
ensure
  self.template = last_template
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quite simple indeed.  Now let&#8217;s see exactly what we are doing to the template.  The first thing we do is send the method &lt;code&gt;_evaluate_assigns_and_ivars&lt;/code&gt; to the view.  This is private method in ActionView::Base which creates instance variables for each key in the &lt;code&gt;`assigns@ attribute hash.  This hash is filled with our&lt;/code&gt;body&lt;code&gt;call in the mailer model you create.  Here is&lt;/code&gt;&lt;em&gt;evaluate&lt;/em&gt;assigns&lt;em&gt;and&lt;/em&gt;ivars`:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 307 action_pack/action_view/base.rb)
def _evaluate_assigns_and_ivars #:nodoc:
 unless @assigns_added
   @assigns.each { |key, value| instance_variable_set("@#{key}", value) }
   _copy_ivars_from_controller
   @assigns_added = true
 end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the instance variables are set, we call &lt;code&gt;_copy_ivars_from_controller&lt;/code&gt; which does exactly that, copies the instance variables from this view&#8217;s controller to this view.  This is how instance variables that you create in normal controller methods are accessed in the view.  Let&#8217;s look at that definition:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 315 action_pack/action_view/base.rb)
def _copy_ivars_from_controller #:nodoc:
  if @controller
    variables = @controller.instance_variable_names
    variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables)
    variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) }
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This method finds all proper instance variables in the attached controller and sets the same instance variables in the current view object.  Once we have copied the instance variables we move to the next line in &lt;code&gt;render&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is another private method in &lt;code&gt;ActionView::Base&lt;/code&gt; and it&#8217;s job is quite simple: set the content_type for the response attribute if this view&#8217;s controller has one.  Let&#8217;s look at the code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 323 action_pack/action_view/base.rb)
def _set_controller_content_type(content_type) #:nodoc:
  if controller.respond_to?(:response)
    controller.response.content_type ||= content_type
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our case, the controller is the &lt;code&gt;MessageMailer&lt;/code&gt; object and it doesnt respond to &lt;code&gt;response&lt;/code&gt; so we dont set a content_type.  Now we come back to &lt;code&gt;render&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# (line 193 action_pack/action_view/renderable.rb)
def render(view, local_assigns = {})
  ...
  view.with_template self do
    ...
    view.send(method_name(local_assigns), local_assigns) do |*names|
      ivar = :@_proc_for_layout
      if !view.instance_variable_defined?(:"@content_for_#{names.first}") &amp;&amp; view.instance_variable_defined?(ivar) &amp;&amp; (proc = view.instance_variable_get(ivar))
        view.capture(*names, &amp;proc)
      elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
        view.instance_variable_get(ivar)
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The next thing we are going to do is call our dynamically generated (and now compiled) view method for this template.  We call it with a block that is used to capture content pieces that this view may use (think &lt;code&gt;content_for&lt;/code&gt;).  AM does not use any of these so we end up skipping over this whole section and just executing our template method.  In a future series on &lt;code&gt;ActionController&lt;/code&gt;, we will dive more into what the block does and how Rails uses it&#8217;s information, but for now we will move on.&lt;/p&gt;

&lt;p&gt;So what exactly did we do when we called that dynamically generated method?  Let&#8217;s find out.  First, we will look at our method again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def _run_erb_app47views47message_mailer47contact_form46erb(local_assigns)
        old_output_buffer = output_buffer;;@output_buffer = '';  __in_erb_template=true ; @output_buffer.concat "Hi,\n"
@output_buffer.concat "\n"
@output_buffer.concat "I am contacting you with this message:\n"
@output_buffer.concat "\n"
@output_buffer.concat(( @message ).to_s); @output_buffer.concat "\n"
@output_buffer.concat "\n"
@output_buffer.concat "\n"
@output_buffer.concat "\n"@output_buffer.concat "Thanks\n"
@output_buffer.concat "\n"
@output_buffer.concat "Jake"; @output_buffer
ensure
  self.output_buffer = old_output_buffer
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remember that &lt;code&gt;output_buffer&lt;/code&gt; is an attribute inside of &lt;code&gt;ActionView::Base&lt;/code&gt; and that it holds the current output for the view that is being processed.  Our dynamic method first stores the current &lt;code&gt;output_buffer&lt;/code&gt; and then resets it so that it can insert the newly parsed message.  When we execute our method, we &lt;code&gt;concat&lt;/code&gt; our entire view (with any ruby processing) into the &lt;code&gt;output_buffer&lt;/code&gt;. So after we execute &lt;code&gt;_run_erb_app47views47message_mailer47contact_form46erb&lt;/code&gt; our output_buffer buffer looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@output_buffer =&gt; "Hi,\n\nI am contacting you with this message:\n\nSend this message\n\n\n\nThanks\n\nJake"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which is the final email body that will be sent. &lt;/p&gt;

&lt;p&gt;Alright, now we have rendered our message and we hit the bottom of this method chain.  We now pop  all the way back up &lt;code&gt;create!&lt;/code&gt;. I know, I know. It was so long ago that you dont remember.  Here is a refresher:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 458 action_mailer/base.rb)
def create!(method_name, *parameters) #:nodoc:
  unless String === @body
    ...
    @body = render_message(@template, @body) if template_exists

    if !@parts.empty? &amp;&amp; String === @body
      @parts.unshift Part.new(:charset =&gt; charset, :body =&gt; @body)
      @body = nil
    end
  end

  @mime_version ||= "1.0" if !@parts.empty?

  @mail = create_mail
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We just got through with &lt;code&gt;render_message&lt;/code&gt; and now we have our &lt;code&gt;@body&lt;/code&gt; attribute filled with our message.  The next line checks to see if we have parts and if we have a body that&#8217;s a String.  If we do, we create a new Part with the current &lt;code&gt;@body&lt;/code&gt; and add it to all of our parts.  After that, we get rid of &lt;code&gt;@body&lt;/code&gt;.  We do this so that &lt;code&gt;create_mail&lt;/code&gt; doesnt try and rerender the body again if we have other parts.  Since we dont, we skip over this and go straight to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@mail = create_mail
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we&#8217;re gettin&#8217; somewhere.  This starts the actual email processing part of AM.  Let&#8217;s see &lt;code&gt;create_mail&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 638 action_mailer/base.rb)
def create_mail
  m = TMail::Mail.new

  m.subject,     = quote_any_if_necessary(charset, subject)
  m.to, m.from   = quote_any_address_if_necessary(charset, recipients, from)
  m.bcc          = quote_address_if_necessary(bcc, charset) unless bcc.nil?
  m.cc           = quote_address_if_necessary(cc, charset) unless cc.nil?
  m.reply_to     = quote_address_if_necessary(reply_to, charset) unless reply_to.nil?
  m.mime_version = mime_version unless mime_version.nil?
  m.date         = sent_on.to_time rescue sent_on if sent_on

  headers.each { |k, v| m[k] = v }

  real_content_type, ctype_attrs = parse_content_type

  if @parts.empty?
    m.set_content_type(real_content_type, nil, ctype_attrs)
    m.body = normalize_new_lines(body)
  else
    if String === body
      part = TMail::Mail.new
      part.body = normalize_new_lines(body)
      part.set_content_type(real_content_type, nil, ctype_attrs)
      part.set_content_disposition "inline"
      m.parts &lt;&lt; part
    end

    @parts.each do |p|
      part = (TMail::Mail === p ? p : p.to_mail(self))
      m.parts &lt;&lt; part
    end

    if real_content_type =~ /multipart/
      ctype_attrs.delete "charset"
      m.set_content_type(real_content_type, nil, ctype_attrs)
    end
  end

  @mail = m
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first thing we do is initialize a new &lt;code&gt;TMail::Mail&lt;/code&gt; instance and then we go on to assign several attributes for it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;m.subject,     = quote_any_if_necessary(charset, subject)
m.to, m.from   = quote_any_address_if_necessary(charset, recipients, from)
m.bcc          = quote_address_if_necessary(bcc, charset) unless bcc.nil?
m.cc           = quote_address_if_necessary(cc, charset) unless cc.nil?
m.reply_to     = quote_address_if_necessary(reply_to, charset) unless reply_to.nil?
m.mime_version = mime_version unless mime_version.nil?
m.date         = sent_on.to_time rescue sent_on if sent_on
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;quote_any_if_necessary&lt;/code&gt;, &lt;code&gt;quote_any_address_if_necessary&lt;/code&gt; and &lt;code&gt;quote_address_if_necessary&lt;/code&gt; are helper methods included from the module &lt;code&gt;ActionMailer::Quoting&lt;/code&gt;.  Let&#8217;s take a gander at those methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 5 action_mailer/quoting.rb)

def quoted_printable(text, charset)
  text = text.gsub( /[^a-z ]/i ) { quoted_printable_encode($&amp;) }.gsub( / /, "_" )
  "=?#{charset}?Q?#{text}?="
end

def quoted_printable_encode(character)
  result = ""
  character.each_byte { |b| result &lt;&lt; "=%02X" % b }
  result
end

if !defined?(CHARS_NEEDING_QUOTING)
  CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/
end

def quote_if_necessary(text, charset)
  text = text.dup.force_encoding(Encoding::ASCII_8BIT) if text.respond_to?(:force_encoding)

  (text =~ CHARS_NEEDING_QUOTING) ?
    quoted_printable(text, charset) :
    text
end

def quote_any_if_necessary(charset, *args)
  args.map { |v| quote_if_necessary(v, charset) }
end

def quote_address_if_necessary(address, charset)
  if Array === address
    address.map { |a| quote_address_if_necessary(a, charset) }
  elsif address =~ /^(\S.*)\s+(&lt;.*&gt;)$/
    address = $2
    phrase = quote_if_necessary($1.gsub(/^['"](.*)['"]$/, '\1'), charset)
    "\"#{phrase}\" #{address}"
  else
    address
  end
end

def quote_any_address_if_necessary(charset, *args)
  args.map { |v| quote_address_if_necessary(v, charset) }
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Im not going to bore you with the inane details, needless to say, these methods take illegal characters and quote them if necessary.  Once these are quoted and sanitized, they are inserted into the Mail object.  After we initialize those attributes, we set the header attributes for the Mail object with the following line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;headers.each { |k, v| m[k] = v }

real_content_type, ctype_attrs = parse_content_type
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We cycle through all the headers of our mailer object and stick them into the TMail::Mail object.  Next we call &lt;code&gt;parse_content_type&lt;/code&gt; which is a private method that we get from &lt;code&gt;ActionMailer::PartContainer&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(line 43 action_mailer/part_container.rb)
def parse_content_type(defaults=nil)
  if content_type.blank? 
    return defaults ? 
      [ defaults.content_type, { 'charset' =&gt; defaults.charset } ] : 
      [ nil, {} ] 
  end 
  ctype, *attrs = content_type.split(/;\s*/)
  attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
  [ctype, {"charset" =&gt; charset || defaults &amp;&amp; defaults.charset}.merge(attrs)]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All we are doing here is parsing the content&lt;em&gt;type of the mailer (in our case &#8220;text/plain&#8221;) and returning an array with the content&lt;/em&gt;type and a hash.  Let&#8217;s see what our example ends up returning:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;parse_content_type =&gt; ["text/plain", {"charset"=&gt;"utf-8"}]
real_content_type =&gt; "text/plain"
ctype_attrs =&gt; {"charset"=&gt;"utf-8"}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we move on to: &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if @parts.empty?
  m.set_content_type(real_content_type, nil, ctype_attrs)
  m.body = normalize_new_lines(body)
else
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our case, &lt;code&gt;@parts&lt;/code&gt; is empty so we set the content type of our TMail object with the results from our parsing.  After that, we set the body of the TMail object to the current AM object&#8217;s body, but we first do some sanitation duties with &lt;code&gt;normalize_new_lines&lt;/code&gt; which is a method in ActionMailer::Utils.  In fact, it is the only method in that module:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(action_mailer/utils.rb)
module ActionMailer
  module Utils #:nodoc:
    def normalize_new_lines(text)
      text.to_s.gsub(/\r\n?/, "\n")
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What we are doing here is cleansing Microsoft evil from the message.  Windows likes to use &#8220;\r\n&#8221; for line breaks in text, the rest of computing thinks it&#8217;s enough to just use &#8220;\n&#8221;.  I agree with the rest of computing.  Anyway, this method changes all &#8220;\r\n&#8220;&#8216;s to &#8220;\n&#8220;&#8216;s so that our email message parses correctly on all email servers.&lt;/p&gt;

&lt;p&gt;After we normalize, we are done with setting up the object and the final line of &lt;code&gt;create_mail&lt;/code&gt; is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@mail = m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we set the AM attribute &lt;code&gt;@mail&lt;/code&gt; to the newly instantiated TMail object and we&#8217;re done&#8230; with the creation of the email message.  Now we have to actually send it.  We&#8217;ll get to that next.  See ya then.&lt;/p&gt;



</description>
      <pubDate>Sun, 06 Dec 2009 09:42:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:a95502ca-484a-400f-b3dc-182d1db922ab</guid>
      <author>jake</author>
      <link>http://blog.flvorful.com/articles/2009/12/06/deep-in-rails-actionmailer-deliver-part-iv</link>
      <category>Rails</category>
      <category>rails</category>
      <category>action_mailer</category>
      <category>deep</category>
      <category>DIR</category>
      <category>part4</category>
    </item>
  </channel>
</rss>
