Class: MailBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/mail_builder.rb,
lib/mail_builder/attachment.rb

Overview

MailBuilder is a library for building RFC compliant MIME messages, with support for text and HTML emails, as well as attachments.

Basic Usage:

mail = MailBuilder.new
mail.to = "[email protected]"
mail.text = "Body"

sendmail = IO.popen("#{`which sendmail`.chomp} -i -t", "w+")
sendmail.puts mail
sendmail.close

# or

require 'net/smtp'

Net::SMTP.start("smtp.address.com", 25) do |smtp|
  smtp.send_message(mail.to_s, mail.from, mail.to)
end

Defined Under Namespace

Classes: Attachment

Constant Summary collapse

BOUNDARY_CHARS =

Boundary characters, slightly adapted from those allowed by rfc1341, representing:

ALPHA / DIGIT / "'" / "(" / ")" / "*" / "," / "-" / "." / "/" / ":"

See 7.2.1, www.w3.org/Protocols/rfc1341/7_2_Multipart.html

((39..58).to_a + (65..90).to_a + (97..122).to_a).map { |_| _.chr }.freeze
ENVELOPE_CHARS =

Valid characters for an envelope_id

BOUNDARY_CHARS - ["+"]
CHARSET =
'utf-8'.freeze
RFC2047_REPLACEMENTS =

Printable characters which RFC 2047 says must be escaped.

[
  ['?', '=%X' % ??],
  ['_', '=%X' % ?_],
  [' ', '_'],
  [/=$/, '']
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ MailBuilder

Accepts an options hash, setting text and html if provided, and setting any provided headers.

mailer = MailBuilder.new(:text => "Text", :to => "[email protected]", "X-Priority" => 1)
mailer.text # => "Text"
mailer.to # => "[email protected]"
mailer.get_header("X-Priority") # => 1


77
78
79
80
81
82
83
84
# File 'lib/mail_builder.rb', line 77

def initialize(options = {})
  @headers = []
  @attachments = []
  @text = nil
  @html = nil

  parse_options(options)
end

Instance Attribute Details

#attachmentsObject (readonly)

Returns the value of attribute attachments.



66
67
68
# File 'lib/mail_builder.rb', line 66

def attachments
  @attachments
end

#headersObject (readonly)

Returns the value of attribute headers.



66
67
68
# File 'lib/mail_builder.rb', line 66

def headers
  @headers
end

#htmlObject

Returns the value of attribute html.



65
66
67
# File 'lib/mail_builder.rb', line 65

def html
  @html
end

#textObject

Returns the value of attribute text.



65
66
67
# File 'lib/mail_builder.rb', line 65

def text
  @text
end

Instance Method Details

#add_header(key, value) ⇒ Object

Adds a header value to the mailer’s headers, without removing previous values.

mailer.add_header("From", "[email protected]")
mailer.add_header("From", "[email protected]")

mailer.headers # => [["From", "[email protected]"], ["From", "[email protected]"]]


95
96
97
# File 'lib/mail_builder.rb', line 95

def add_header(key, value)
  @headers << [key.to_s, value]
end

#attach(file, type = nil, headers = nil) ⇒ Object

Wrapper for attach_as, setting the attachment filename to the file’s basename.

mailer.attach "some/file.pdf"


155
156
157
158
159
# File 'lib/mail_builder.rb', line 155

def attach(file, type = nil, headers = nil)
  file = Pathname(file)

  attach_as(file, file.basename, type, headers)
end

#attach_as(file, name, type = nil, headers = nil) ⇒ Object

Adds an Attachment to the email.

If file is an IO or File object, it’s contents will be read immediately, in case the mail will be delivered to an external service without access to the object. Otherwise, the attached file’s content will be read when the message is built.

If no type is provided, the MIME::Types library will be used to find a suitable content type.

mailer.attach "account.html"
mailer.attach_as StringIO.new("test"), "account.txt"


175
176
177
# File 'lib/mail_builder.rb', line 175

def attach_as(file, name, type = nil, headers = nil)
  @attachments << Attachment.new(file, name, type, headers)
end

#attachments?Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/mail_builder.rb', line 183

def attachments?
  @attachments.any?
end

#buildObject Also known as: to_s

Builds the full email message suitable to be passed to Sendmail, Net::SMTP, etc.

It sets the Mail-From header (used for tracking emails), date, and message id, and then assembles the headers, body, and attachments.

All expensive operations – generating boundaries, rendering views, reading attached files – are delayed until this method is called.



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/mail_builder.rb', line 196

def build
  set_header("Mail-From", "#{ENV["USER"]}@localhost ENVID=#{envelope_id}")
  set_header("Date", Time.now.rfc2822)
  set_header("Message-ID", "<#{Time.now.to_f}.#{Process.pid}@#{get_header("from").to_s.split("@", 2)[1]}>")

  if multipart?
    set_header("Mime-Version", "1.0")
    if attachments?
      set_header("Content-Type", "multipart/mixed; boundary=\"#{attachment_boundary}\"")
    else
      set_header("Content-Type", "multipart/alternative; boundary=\"#{body_boundary}\"")
    end
  end

  build_headers + build_body
end

#envelope_idObject

Returns the envelope id for this mailer. The mail spec’s ENV_ID is used to provide a unique identifier that follows an email through it’s various states – including bounces – allowing it to be tracked.



132
133
134
# File 'lib/mail_builder.rb', line 132

def envelope_id
  @envelope_id ||= (1..25).to_a.map { ENVELOPE_CHARS[rand(ENVELOPE_CHARS.size)] }.join
end

#get_header(key) ⇒ Object Also known as: []

Retrieves a value from the mailer’s headers.

mailer.get_header("to") # => "[email protected]"


104
105
106
# File 'lib/mail_builder.rb', line 104

def get_header(key)
  @headers.detect { |k, v| return v if k == key }
end

#headerObject

We define getters and setters for commonly used headers.



139
140
141
142
143
144
145
146
147
# File 'lib/mail_builder.rb', line 139

%w(from to cc bcc reply_to subject).each do |header|
  define_method(header) do
    get_header(header)
  end

  define_method(header + "=") do |value|
    set_header(header, value)
  end
end

#multipart?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/mail_builder.rb', line 179

def multipart?
  attachments? || @html
end

#remove_header(key) ⇒ Object



109
110
111
# File 'lib/mail_builder.rb', line 109

def remove_header(key)
  @headers.reject! { |k,| k == key }
end

#set_header(key, value) ⇒ Object Also known as: []=

Adds a header value to the mailer’s headers, replacing previous values.

mailer.add_header("From", "[email protected]")
mailer.set_header("From", "[email protected]")

mailer.headers # => [["From", "[email protected]"]]


121
122
123
124
# File 'lib/mail_builder.rb', line 121

def set_header(key, value)
  remove_header(key)
  add_header(key, value)
end