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
62
# File 'lib/mailfactory.rb', line 54

def initialize()
	@headers = Array.new()
	@attachments = Array.new()
	@attachmentboundary = generate_boundary()
	@bodyboundary = generate_boundary()
	@html = nil
	@text = nil
               @charset = 'utf-8'
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)



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mailfactory.rb', line 124

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.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/mailfactory.rb', line 246

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.



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
305
306
307
308
# File 'lib/mailfactory.rb', line 277

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



66
67
68
69
70
71
# File 'lib/mailfactory.rb', line 66

def add_header(header, value)
               value = quote_if_necessary(value, @charset) if header == 'subject'
               value = quote_address_if_necessary(value, @charset) if header == 'from'
               value = quote_address_if_necessary(value, @charset) if header == 'to'
	@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)



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
208
209
210
211
# File 'lib/mailfactory.rb', line 177

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



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/mailfactory.rb', line 221

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



151
152
153
154
155
156
157
158
159
160
161
# File 'lib/mailfactory.rb', line 151

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



110
111
112
# File 'lib/mailfactory.rb', line 110

def html=(newhtml)
	@html = "<html>\n<head>\n<meta content=\"text/html;charset=#{@charset}\" 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)


165
166
167
168
169
170
171
# File 'lib/mailfactory.rb', line 165

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



116
117
118
# File 'lib/mailfactory.rb', line 116

def rawhtml=(newhtml)
	@html = newhtml
end

#remove_header(header) ⇒ Object

removes the named header - case insensitive



75
76
77
78
79
80
81
# File 'lib/mailfactory.rb', line 75

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

#replytoObject



97
98
99
# File 'lib/mailfactory.rb', line 97

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

#replyto=(newreplyto) ⇒ Object



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

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)



85
86
87
88
# File 'lib/mailfactory.rb', line 85

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

#text=(newtext) ⇒ Object

sets the plain text body of the message



103
104
105
# File 'lib/mailfactory.rb', line 103

def text=(newtext)
	@text = newtext
end

#to_sObject

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



215
216
217
# File 'lib/mailfactory.rb', line 215

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