| Class | Sendmail |
| In: |
lib/sendmail.rb
|
| Parent: | Object |
| MAIL_FILE | = | Pathname.new(',mail') |
# File lib/sendmail.rb, line 110 def check_mail_options ( options ) raise ArgumentError, 'No recipents' if options.to.empty? raise ArgumentError, 'No mail server' if options.server.nil? raise ArgumentError, 'No mail subject' if options.header[:Subject].nil? end
# File lib/sendmail.rb, line 16 def parse_mail_options ( *args ) options = OpenStruct.new( :from => (defined? EMAIL)? EMAIL : ENV['EMAIL'], :from_name => (defined? FULLNAME)? FULLNAME : ENV['FULLNAME'], :to => [], :server => ENV['SMTPSERVER'] || 'localhost:25', :header => {}, :body => STDIN, :charset => 'us-ascii', :encoding => '7bit' ) string_args, hash_args = args.partition { |x| x.is_a?(String) } hash_args.each do |hash| raise ArgumentError, "Bad argument #{hash}" unless hash.is_a?(Hash) if hash[:header].is_a? String options.header.merge! YAML.load(hash[:header]).symbolize_keys hash.delete :header end if hash[:subject] options.header[:Subject] = hash[:subject] hash.delete :subject end hash.each do |k,v| x = options.send(k) case x when Hash then v.each { |kk, vv| x[kk.to_sym] = vv } when Array then x.concat v else options.send("#{k}=", v) end end end OptionParser.new do |opts| opts.separator '' opts.on('-b', '--body FILE', 'Choose a file for the mail body') do |aFile| options.body = File.open(aFile) end opts.on('-f', '--mail-from NAME <EMAIL>', 'Choose the From address') do |aString| options.from = aString end opts.on('-t', '--mail-to NAME', 'Choose a recipient') do |aString| options.to << aString end opts.on('-s', '--server NAME:PORT', 'Choose a mail server') do |aString| options.server, options.port = aString.split(/:/) options.port ||= 25 end opts.on('-S', '--subject NAME', 'Choose your mail subject') do |aString| options.header[:Subject] = aString.sub(/\.?$/, '.') end opts.on('--[no-]sign', 'Sign the message with gpg') do |signed| options.signed = signed end opts.on('--passphrase FILE', 'the passphrase file') do |aFile| options.pass = Pathname.new(aFile) end opts.on('-a', '--[no-]confirm', 'Ask a confirmation before sending') do |confirm| options.confirm = confirm end opts.on('--comment STRING', 'Choose a comment for GPG') do |aComment| options.comment = aComment end opts.on('--header STRING', 'Add some header fields (Yaml syntax)') do |s| options.header.merge! YAML.load(s) end opts.on('-m', '--[no-]mime', 'Choose the MIME protocol') do |mime| options.mime = mime end opts.on('--charset STRING', 'Choose a charset for the encoding') do |aCharset| options.charset = aCharset end opts.on('--encoding STRING', 'Choose an encoding') do |anEncoding| options.encoding = anEncoding end opts.on_tail('-h', '--help', 'Show this message') do puts opts exit end end.parse!(string_args) options.header[:To] = (options.header[:To] || options.to).join(', ') from = options.header[:From] || options.from if from.to_s =~ /<(.*)>/ options.header[:From] = from options.from = $1 else options.header[:From] = "#{options.from_name} <#{from}>" options.from = from end check_mail_options(options) options end
Mail.
# File lib/sendmail.rb, line 119 def sendmail ( *args ) body, opts = nil, nil if MAIL_FILE.exist? STDERR.puts "Using the cache file #{MAIL_FILE}" MAIL_FILE.open do |mail_file| opts = YAML::chop_header(mail_file) body = mail_file.read end else opts = parse_mail_options(*args) body = (opts.body.nil?)? '' : opts.body.read end opts.header.symbolize_keys! server, port = opts.server.split(/:/) port ||= 25 to = opts.header[:To] to = to.join(', ') if to.is_a? Array STDERR.puts "To: #{to.inspect}" STDERR.puts "Smtp Server: #{server}" # # confirm the user # if opts.confirm raise 'HighLine is unavailable' unless defined? HighLine question = %Q[ |Send a mail, with this subject: #{opts.header[:Subject]} | to #{to} | from #{opts.header[:From]} | #{(opts.signed)? 'signed by ' + opts.from : 'not signed !'} |Are you sure? (y/n)].head_cut! raise 'Aborting' unless HighLine.new.agree question, true end require 'net/smtp' Net::SMTP.start(server, port) do |smtp| smtp.open_message_stream(opts.from, opts.to) do |f| f.print "From: #{opts.header[:From]}\n" f.print "To: #{to}\n" f.print "Subject: #{opts.header[:Subject]}\n" opts.header.each do |k, v| next if [:From, :To, :Subject].include? k k = $1 if k.to_s =~ /^"(.*)"$/ f.print "#{k}: #{v}\n" end if opts.signed TempPath.new do |mail_body| mail_body.open('w') do |out| if opts.mime out.puts " |Content-Type: text/plain; charset=\"#{opts.charset}\" |Content-Transfer-Encoding: #{opts.encoding} | |".head_cut! end out.print body end f.print sign_wrap(opts, mail_body) end else f.print "\n" + body end end end end
# File lib/sendmail.rb, line 193 def sign_wrap ( opts, body ) id = "===============Vcs#{new_id 10}==" if opts.mime TempPath.new do |tmp_name| tmp_name.open('w') do |tmp| if opts.mime tmp.print %Q[ |MIME-Version: 1.0 |Content-Type: multipart/signed; micalg=pgp-sha1; | protocol="application/pgp-signature"; | boundary="#{id}"; | charset="#{opts.charset}" |Content-Transfer-Encoding: #{opts.encoding} | |This is an OpenPGP/MIME signed message (RFC 2440 and 3156) |--#{id} |].head_cut! tmp.print body.read tmp.print %Q[ | |--#{id} |Content-Type: application/pgp-signature; name="signature.asc" |Content-Description: OpenPGP digital signature |Content-Disposition: attachment; filename="signature.asc" | |].head_cut! end TempPath.new do |tmp_out| pid = fork do cmd = %w[ gpg --status-fd 2 --sign --textmode --armor --digest-algo sha1 --no-use-agent -u ] cmd << "<#{opts.from}>" cmd << ((opts.mime)? '--detach-sign' : '--clearsign') cmd += [ '--output', tmp_out ] if opts.pass cmd += [ '--no-tty', '--batch', '--passphrase-fd', opts.pass.open.to_i.to_s ] end cmd += [ '--comment', "'#{opts.comment}'" ] if opts.comment STDIN.reopen(body.open) exec(*cmd) end Process.waitpid pid tmp.print tmp_out.read tmp.puts "\n--#{id}--" if opts.mime end end return tmp_name.read end end