Write a function to send an email. The function should have parameters for setting From, To and Cc addresses; the Subject, and the message text, and optionally fields for the server name and login details.

  • If appropriate, explain what notifications of problems/success are given.
  • Solutions using libraries or functions from the language are preferred, but failing that, external programs can be used with an explanation.
  • Note how portable the solution given is between operating systems when multi-OS languages are used.
Task
Send email
You are encouraged to solve this task according to the task description, using any language you may know.

(Remember to obfuscate any sensitive data used in examples)

Mathematica

Mathematica has the built-in function SendMail, example: <lang Mathematica> SendMail["From" -> "from@email.com", "To" -> "to@email.com",

"Subject" -> "Sending Email from Mathematica", "Body" -> "Hello world!", 
"Server" -> "smtp.email.com"]

</lang> The following options can be specified: <lang Mathematica> "To" "Cc" "Bcc" "Subject" "Body" "Attachments" "From" "Server" "EncryptionProtocol" "Fullname" "Password" "PortNumber" "ReplyTo" "ServerAuthentication" "UserName" </lang> Possible options for EncryptionProtocol are: "SSL","StartTLS" and "TLS". This function should work fine on all the OS's Mathematica runs, which includes the largest 3: Windows, Linux, Mac OSX.

Python

The function returns a dict of any addresses it could not forward to; other connection problems raise errors.
Tested on Windows, it should work on POSIX platforms too.

<lang python>import smtplib

def sendemail(from_addr, to_addr_list, cc_addr_list,

             subject, message,
             login, password,
             smtpserver='smtp.gmail.com:587'):
   header  = 'From: %s\n' % from_addr
   header += 'To: %s\n' % ','.join(to_addr_list)
   header += 'Cc: %s\n' % ','.join(cc_addr_list)
   header += 'Subject: %s\n\n' % subject
   message = header + message
   
   server = smtplib.SMTP(smtpserver)
   server.starttls()
   server.login(login,password)
   problems = server.sendmail(from_addr, to_addr_list, message)
   server.quit()
   return problems</lang>

Example use: <lang python>sendemail(from_addr = 'python@RC.net',

         to_addr_list = ['RC@gmail.com'],
         cc_addr_list = ['RC@xx.co.uk'], 
         subject      = 'Howdy', 
         message      = 'Howdy from a python function', 
         login        = 'pythonuser', 
         password     = 'XXXXX')

</lang>

Sample Email received:

Message-ID: <4a4a1e78.0717d00a.1ba8.ffcfdbdd@xx.google.com>
Date: Tue, 30 Jun 2009 22:04:56 -0700 (PDT)
From: python@RC.net
To: RC@gmail.com
Cc: RC@xx.co.uk
Subject: Howdy

Howdy from a python function

Ruby

Uses the

Library: RubyGems

gem TMail

<lang ruby>require 'base64' require 'net/smtp'

require 'rubygems' require 'tmail'

module SendEmail

 def self.send_email(from, to, subject, body, options={})
   opts = handle_options(options)
   msg = build_email(from, to, subject, body, opts)
   args = [opts[:server], opts[:port], opts[:helo], opts[:username], opts[:password], opts[:authtype]]
   Net::SMTP.start(*args) do |smtp|
     smtp.send_message(msg.to_s, msg.from[0], msg.to)
   end
 end
 def self.handle_options(options)
   opts = {:attachments => [], :server => 'localhost'}
   unless options.nil?
     options.each do |key, value|
       # ensure keys are lower case symbols
       opts[key.to_s.downcase.to_sym] = value
     end
   end
   opts
 end
 def self.build_email(from, to, subject, body, opts)
   msg = TMail::Mail.new
   msg.from    = from
   msg.to      = to
   msg.subject = subject
   msg.body    = body
   msg.cc      = opts[:cc]  if opts[:cc]
   msg.bcc     = opts[:bcc] if opts[:bcc]
   # attach attachments
   opts[:attachments].select {|file| File.readable?(file)}.each do |file|
     attach = TMail::Mail.new
     attach.body = Base64.encode64(File.read(file))
     attach.transfer_encoding = 'base64'
     attach.set_disposition("attachment", {:filename => file})
     msg.parts << attach
   end
   msg
 end

end

SendEmail.send_email(

 'sender@sender.invalid',
 %w{ recip1@recipient.invalid recip2@example.com },
 'the subject',
 "the body\nhas lines",
 {
   :attachments => %w{ file1 file2 file3 },
   :server => 'mail.example.com',
   :helo => 'sender.invalid',
   :username => 'user',
   :password => 'secret'
 }

)</lang>

Tcl

Library: tcllib

Also may use the tls package (needed for sending via gmail). <lang tcl>package require smtp package require mime package require tls

set gmailUser ******* set gmailPass hunter2; # Hello, bash.org!

proc send_simple_message {recipient subject body} {

   global gmailUser gmailPass
   # Build the message
   set token [mime::initialize -canonical text/plain -string $body]
   mime::setheader $token Subject $subject
   # Send it!
   smtp::sendmessage $token -userame $gamilUser -password $gmailPass \
           -recipients $recipient -servers smtp.gmail.com -ports 587
   # Clean up
   mime::finalize $token

}

send_simple_message recipient@example.com "Testing" "This is a test message."</lang>