Class: MailFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/mailfactory.rb

Overview

An easy class for creating a mail message

Instance Method Summary collapse

Constructor Details

#initializeMailFactory

Returns a new instance of MailFactory.



54
55
56
57
58
59
60
61
# File 'lib/mailfactory.rb', line 54

def initialize()
	@headers = Array.new()
	@attachments = Array.new()
	@attachmentboundary = generate_boundary()
	@bodyboundary = generate_boundary()
	@html = nil
	@text = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(methId, *args) ⇒ Object

implement method missing to provide helper methods for setting and getting headers. Headers with ‘-’ characters may be set/gotten as ‘x_mailer’ or ‘XMailer’ (splitting will occur between capital letters or on ‘_’ chracters)



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/mailfactory.rb', line 120

def method_missing(methId, *args)
	name = methId.id2name()
	
	# mangle the name if we have to
	if(name =~ /_/)
		name = name.gsub(/_/, '-')
	elsif(name =~ /[A-Z]/)
		name = name.gsub(/([a-zA-Z])([A-Z])/, '\1-\2')
	end
	
	# determine if it sets or gets, and do the right thing
	if(name =~ /=$/)
		if(args.length != 1)
			super(methId, args)
		end
		set_header(name[/^(.*)=$/, 1], args[0])			
	else
		if(args.length != 0)
			super(methId, args)
		end
		headers = get_header(name)
		return(get_header(name))
	end
end

Instance Method Details

#add_attachment(filename, type = nil, attachmentheaders = nil) ⇒ Object Also known as: attach

adds an attachment to the mail. Type may be given as a mime type. If it is left off and the MIME::Types module is available it will be determined automagically. If the optional attachemntheaders is given, then they will be added to the attachment boundary in the email, which can be used to produce Content-ID markers. attachmentheaders can be given as an Array or a String.



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/mailfactory.rb', line 242

def add_attachment(filename, type=nil, attachmentheaders = nil)
	attachment = Hash.new()
	attachment['filename'] = Pathname.new(filename).basename
	if(type == nil)
		attachment['mimetype'] = MIME::Types.type_for(filename).to_s
	else
		attachment['mimetype'] = type
	end	
	
	# Open in rb mode to handle Windows, which mangles binary files opened in a text mode
	File.open(filename, "rb") { |fp|
		attachment['attachment'] = file_encode(fp.read())
	}

	if(attachmentheaders != nil)
		if(!attachmentheaders.kind_of?(Array))
			attachmentheaders = attachmentheaders.split(/\r?\n/)
		end
		attachment['headers'] = attachmentheaders
	end

	@attachments << attachment
end

#add_attachment_as(file, emailfilename, type = nil, attachmentheaders = nil) ⇒ Object Also known as: attach_as

adds an attachment to the mail as emailfilename. Type may be given as a mime type. If it is left off and the MIME::Types module is available it will be determined automagically. file may be given as an IO stream (which will be read until the end) or as a filename. If the optional attachemntheaders is given, then they will be added to the attachment boundary in the email, which can be used to produce Content-ID markers. attachmentheaders can be given as an Array of a String.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/mailfactory.rb', line 273

def add_attachment_as(file, emailfilename, type=nil, attachmentheaders = nil)
	attachment = Hash.new()
	attachment['filename'] = emailfilename

	if(type != nil)
		attachment['mimetype'] = type.to_s()
	elsif(file.kind_of?(String) or file.kind_of?(Pathname))
		attachment['mimetype'] = MIME::Types.type_for(file.to_s()).to_s
	else
		attachment['mimetype'] = ''
	end
	
	if(file.kind_of?(String) or file.kind_of?(Pathname))		
		# Open in rb mode to handle Windows, which mangles binary files opened in a text mode
		File.open(file.to_s(), "rb") { |fp|
			attachment['attachment'] = file_encode(fp.read())
		}
	elsif(file.respond_to?(:read))
		attachment['attachment'] = file_encode(file.read())
	else
		raise(Exception, "file is not a supported type (must be a String, Pathnamem, or support read method)")
	end
	
	if(attachmentheaders != nil)
		if(!attachmentheaders.kind_of?(Array))
			attachmentheaders = attachmentheaders.split(/\r?\n/)
		end
		attachment['headers'] = attachmentheaders
	end
	
	@attachments << attachment
end

#add_header(header, value) ⇒ Object

adds a header to the bottom of the headers



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

def add_header(header, value)
	@headers << "#{header}: #{value}"
end

#construct(options = Hash.new) ⇒ Object

builds an email and returns it as a string. Takes the following options:

:messageid

Adds a message id to the message based on the from header (defaults to false)

:date

Adds a date to the message if one is not present (defaults to true)



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/mailfactory.rb', line 173

def construct(options = Hash.new)
	if(options[:date] == nil)
		options[:date] = true
	end
	
	if(options[:messageid])
		# add a unique message-id
		remove_header("Message-ID")
		sendingdomain = get_header('from')[0].to_s()[/@([-a-zA-Z0-9._]+)/,1].to_s()
		add_header("Message-ID", "<#{Time.now.to_f()}.#{Process.euid()}.#{String.new.object_id()}@#{sendingdomain}>")
	end

	if(options[:date])
		if(get_header("Date").length == 0)
			add_header("Date", Time.now.strftime("%a, %d %b %Y %H:%M:%S %z"))
		end
	end

	# Add a mime header if we don't already have one and we have multiple parts
	if(multipart?())
		if(get_header("MIME-Version").length == 0)
			add_header("MIME-Version", "1.0")
		end
		
		if(get_header("Content-Type").length == 0)
			if(@attachments.length == 0)
				add_header("Content-Type", "multipart/alternative;boundary=\"#{@bodyboundary}\"")
			else
				add_header("Content-Type", "multipart/mixed; boundary=\"#{@attachmentboundary}\"")
			end
		end
	end
	
	return("#{headers_to_s()}#{body_to_s()}")
end

#generate_boundaryObject

generates a unique boundary string



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/mailfactory.rb', line 217

def generate_boundary()
	randomstring = Array.new()
	1.upto(25) {
		whichglyph = rand(100)
		if(whichglyph < 40)
			randomstring << (rand(25) + 65).chr()
		elsif(whichglyph < 70)
			randomstring << (rand(25) + 97).chr()
		elsif(whichglyph < 90)
			randomstring << (rand(10) + 48).chr()
		elsif(whichglyph < 95)
			randomstring << '.'
		else
			randomstring << '_'
		end
	}
	return("----=_NextPart_#{randomstring.join()}")
end

#get_header(header) ⇒ Object

returns the value (or values) of the named header in an array



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/mailfactory.rb', line 147

def get_header(header)
	headers = Array.new()
	headerregex = /^#{Regexp.escape(header)}:/i
	@headers.each() { |h|
		if(headerregex.match(h))
			headers << h[/^[^:]+:(.*)/i, 1].strip()
		end
	}
	
	return(headers)
end

#html=(newhtml) ⇒ Object

sets the HTML body of the message. Only the body of the html should be provided



106
107
108
# File 'lib/mailfactory.rb', line 106

def html=(newhtml)
	@html = "<html>\n<head>\n<meta content=\"text/html;charset=ISO-8859-1\" http-equiv=\"Content-Type\">\n</head>\n<body bgcolor=\"#ffffff\" text=\"#000000\">\n#{newhtml}\n</body>\n</html>"
end

#multipart?Boolean

returns true if the email is multipart

Returns:

  • (Boolean)


161
162
163
164
165
166
167
# File 'lib/mailfactory.rb', line 161

def multipart?()
	if(@attachments.length > 0 or @html != nil)
		return(true)
	else
		return(false)
	end
end

#rawhtml=(newhtml) ⇒ Object

sets the HTML body of the message. The entire HTML section should be provided



112
113
114
# File 'lib/mailfactory.rb', line 112

def rawhtml=(newhtml)
	@html = newhtml
end

#remove_header(header) ⇒ Object

removes the named header - case insensitive



71
72
73
74
75
76
77
# File 'lib/mailfactory.rb', line 71

def remove_header(header)
	@headers.each_index() { |i|
		if(@headers[i] =~ /^#{Regexp.escape(header)}:/i)
			@headers.delete_at(i)
		end
	}
end

#replytoObject



93
94
95
# File 'lib/mailfactory.rb', line 93

def replyto()
	return(get_header("Reply-To")[0])
end

#replyto=(newreplyto) ⇒ Object



87
88
89
90
# File 'lib/mailfactory.rb', line 87

def replyto=(newreplyto)
	remove_header("Reply-To")
	add_header("Reply-To", newreplyto)
end

#set_header(header, value) ⇒ Object

sets a header (removing any other versions of that header)



81
82
83
84
# File 'lib/mailfactory.rb', line 81

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

#text=(newtext) ⇒ Object

sets the plain text body of the message



99
100
101
# File 'lib/mailfactory.rb', line 99

def text=(newtext)
	@text = newtext
end

#to_sObject

returns a formatted email - equivalent to construct(:messageid => true)



211
212
213
# File 'lib/mailfactory.rb', line 211

def to_s()
	return(construct(:messageid => true))
end