Send email: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Ruby}}: handle attachment content-type)
Line 143: Line 143:


=={{header|Ruby}}==
=={{header|Ruby}}==
Uses the {{libheader|RubyGems}} gem [http://tmail.rubyforge.org TMail] which allows us to manipulate email objects conveniently.
Uses the {{libheader|RubyGems}} gems [http://tmail.rubyforge.org TMail] which allows us to manipulate email objects conveniently, and [http://mime-types.rubyforge.org/ mime-types] which guesses a file's mime type based on its filename.

<lang ruby>require 'base64'
<lang ruby>require 'base64'
require 'net/smtp'
require 'net/smtp'
require 'tmail'
require 'tmail'
require 'mime/types'


class Email
class Email
def initialize(from, to, subject, body, options={})
def initialize(from, to, subject, body, options={})
@opts = {:attachments => [], :server => 'localhost'}.update(options)
@opts = {:attachments => [], :server => 'localhost'}.update(options)

@msg = TMail::Mail.new
@msg = TMail::Mail.new
@msg.from = from
@msg.from = from
@msg.to = to
@msg.to = to
@msg.subject = subject
@msg.subject = subject
@msg.body = body
@msg.cc = @opts[:cc] if @opts[:cc]
@msg.cc = @opts[:cc] if @opts[:cc]
@msg.bcc = @opts[:bcc] if @opts[:bcc]
@msg.bcc = @opts[:bcc] if @opts[:bcc]


# attach attachments
if @opts[:attachments].empty?
# just specify the body
@opts[:attachments].select {|file| File.readable?(file)}.each do |file|
attach = TMail::Mail.new
@msg.body = body
else
# attach attachments, including the body
@msg.body = "This is a multi-part message in MIME format.\n"

msg_body = TMail::Mail.new
msg_body.body = body
msg_body.set_content_type("text","plain", {:charset => "ISO-8859-1"})
@msg.parts << msg_body

octet_stream = MIME::Types['application/octet-stream']

@opts[:attachments].select {|file| File.readable?(file)}.each do |file|
mime_type = MIME::Types.type_for(file).first || octet_stream
@msg.parts << create_attachment(file, mime_type)
end
end
end
attr_reader :msg

def create_attachment(file, mime_type)
attach = TMail::Mail.new
if mime_type.binary?
attach.body = Base64.encode64(File.read(file))
attach.body = Base64.encode64(File.read(file))
attach.transfer_encoding = 'base64'
attach.transfer_encoding = 'base64'
else
attach.set_disposition("attachment", {:filename => file})
@msg.parts << attach
attach.body = File.read(file)
end
end
attach.set_disposition("attachment", {:filename => file})
attach.set_content_type(mime_type.media_type, mime_type.sub_type, {:name=>file})
attach
end
end
attr_reader :msg


# instance method to send an Email object
# instance method to send an Email object
def send
def send
args = @opts.values_at(:server, :port, :helo, :username, :password, :authtype)
args = @opts.values_at(:server, :port, :helo, :username, :password, :authtype)
Net::SMTP.start(*args) do |smtp|
Net::SMTP.start(*args) do |smtp|
smtp.send_message(@msg.to_s, @msg.from[0], @msg.to)
smtp.send_message(@msg.to_s, @msg.from[0], @msg.to)
end
end
Line 180: Line 204:


# class method to construct an Email object and send it
# class method to construct an Email object and send it
def self.send(from, to, subject, body, options={})
def self.send(*args)
self.new(from, to, subject, body, options).send
self.new(*args).send
end
end
end
end

Revision as of 19:01, 9 September 2009

Task
Send email
You are encouraged to solve this task according to the task description, using any language you may know.

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.

(Remember to obfuscate any sensitive data used in examples)

AutoHotkey

ahk discussion

Library: COM.ahk

<lang autohotkey>sSubject:= "greeting" sText  := "hello" sFrom  := "ahk@rosettacode" sTo  := "whomitmayconcern"

sServer  := "smtp.gmail.com" ; specify your SMTP server nPort  := 465 ; 25 bTLS  := True ; False inputbox, sUsername, Username inputbox, sPassword, password

COM_Init() pmsg := COM_CreateObject("CDO.Message") pcfg := COM_Invoke(pmsg, "Configuration") pfld := COM_Invoke(pcfg, "Fields")

COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/sendusing", 2) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout", 60) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/smtpserver", sServer) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/smtpserverport", nPort) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/smtpusessl", bTLS) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", 1) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/sendusername", sUsername) COM_Invoke(pfld, "Item", "http://schemas.microsoft.com/cdo/configuration/sendpassword", sPassword) COM_Invoke(pfld, "Update")

COM_Invoke(pmsg, "Subject", sSubject) COM_Invoke(pmsg, "From", sFrom) COM_Invoke(pmsg, "To", sTo) COM_Invoke(pmsg, "TextBody", sText) COM_Invoke(pmsg, "Send")

COM_Release(pfld) COM_Release(pcfg) COM_Release(pmsg) COM_Term()

  1. Include COM.ahk</lang>

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.


OCaml

  • using the library smtp-mail-0.1.3

<lang ocaml>let h = Smtp.connect "smtp.gmail.fr";; Smtp.helo h "hostname";; Smtp.mail h "<john.smith@example.com>";; Smtp.rcpt h "<john-doe@example.com>";; let email_header = "\ From: John Smith <john.smith@example.com> To: John Doe <john-doe@example.com> Subject: surprise";; let email_msg = "Happy Birthday";; Smtp.data h (email_header ^ "\r\n\r\n" ^ email_msg);; Smtp.quit h;;</lang>

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 all POSIX platforms.

<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

R

Library: tcltk
Library: gdata
Library: caTools

R does not have a built-in facility for sending emails though some code for this, written by Ben Bolker, is available here.

Ruby

Uses the

Library: RubyGems

gems TMail which allows us to manipulate email objects conveniently, and mime-types which guesses a file's mime type based on its filename.

<lang ruby>require 'base64' require 'net/smtp' require 'tmail' require 'mime/types'

class Email

 def initialize(from, to, subject, body, options={})
   @opts = {:attachments => [], :server => 'localhost'}.update(options)
   @msg = TMail::Mail.new
   @msg.from    = from
   @msg.to      = to
   @msg.subject = subject
   @msg.cc      = @opts[:cc]  if @opts[:cc]
   @msg.bcc     = @opts[:bcc] if @opts[:bcc]
   if @opts[:attachments].empty?
     # just specify the body
     @msg.body = body
   else
     # attach attachments, including the body
     @msg.body = "This is a multi-part message in MIME format.\n"
     msg_body = TMail::Mail.new
     msg_body.body = body
     msg_body.set_content_type("text","plain", {:charset => "ISO-8859-1"})
     @msg.parts << msg_body
     octet_stream = MIME::Types['application/octet-stream']
     @opts[:attachments].select {|file| File.readable?(file)}.each do |file|
       mime_type = MIME::Types.type_for(file).first || octet_stream
       @msg.parts << create_attachment(file, mime_type)
     end
   end
 end
 attr_reader :msg
 def create_attachment(file, mime_type)
   attach = TMail::Mail.new
   if mime_type.binary?
     attach.body = Base64.encode64(File.read(file))
     attach.transfer_encoding = 'base64'
   else
     attach.body = File.read(file)
   end
   attach.set_disposition("attachment", {:filename => file})
   attach.set_content_type(mime_type.media_type, mime_type.sub_type, {:name=>file})
   attach
 end
 # instance method to send an Email object
 def send
   args = @opts.values_at(:server, :port, :helo, :username, :password, :authtype)
   Net::SMTP.start(*args) do |smtp|
     smtp.send_message(@msg.to_s, @msg.from[0], @msg.to)
   end
 end
 # class method to construct an Email object and send it
 def self.send(*args)
   self.new(*args).send
 end

end

Email.send(

 '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>