Using javamail in jacl

The current version of Jacl (1.4.1) can not use the smtp package in tcllib, because of lack of support for the fileevent command. The email functions of Java are easy to use, however.

The first step is making sure a mail.jar file is in the CLASSPATH. Æjaks has mail-1.4.jar in the jetty-6.0.1/lib/plus directory so nothing extra needs to be done. Other Jacl users may need to download it. [L1 ]

A tiny amount of Java code needs to be used if the email host uses password authentication. The Hyde package in Æjaks makes handling java code straightforward. Its use is shown below.

package require java
package require hyde

hyde::jclass SMTPAuthenticator -extends javax.mail.Authenticator -import {javax.mail.* }  {  
     String userName = " ",
            password = " ";
    public SMTPAuthenticator(String userName, String password) 
    {
       this.userName = userName;
       this.password = password;
    }
        public PasswordAuthentication getPasswordAuthentication()
        { 
            return new PasswordAuthentication(userName, password);
        }
}

The code creates the SMTPAuthenticator class with a constructor which saves the username and password, so that the PasswordAuthentication method can use them when needed.

After that is set up, the following proc can be used to send mail.

proc sendMail args {
# Set up default arguments
  array set opts {  
    -user [email protected] 
    -password *****
    -host smtp.gmail.com 
    -port 465 
    -to [email protected] 
    -subject "Testing email" 
    -text "Not much to say" 
    -auth true 
    -useTLS true
  }
# Minimal error checking: odd number of args, first of pair not a valid option name
  set optsLength [llength [array get opts]
  set optsNames array names opts
  if {llength $args % 2 != 0} {puts "Unpaired option request. Valid options are:\n$optsNames"; return}
  array set opts $args
  if {[llength [array get opts] != $optsLength} {puts "Illegal option request. Valid options are:\n$optsNames"; return}
#  puts array get opts
  
  set props java::new java.util.Properties
  $props put mail.smtp.user $opts(-user)
  $props put mail.smtp.host $opts(-host)
  $props put mail.smtp.port $opts(-port)
  $props put mail.smtp.auth $opts(-auth)
  $props put mail.smtp.starttls.enable $opts(-useTLS)
  $props put mail.smtp.socketFactory.port $opts(-port)
  $props put mail.smtp.socketFactory.class javax.net.ssl.SSLSocketFactory
  $props put mail.smtp.socketFactory.fallback false
  set auth java::new hyde.SMTPAuthenticator $opts(-user) $opts(-password)
  set session java::call javax.mail.Session getInstance $props $auth
  set msg java::new javax.mail.internet.MimeMessage $session
  $msg setText $opts(-text)
  $msg setSubject $opts(-subject)
  $msg setFrom java::new javax.mail.internet.InternetAddress $opts(-user)
  foreach recip $opts(-to) {
    set addressTo java::new javax.mail.internet.InternetAddress $recip
    $msg addRecipient java::field javax.mail.Message.RecipientType TO $addressTo
  }
  java::call javax.mail.Transport send $msg
}

Any or none of the options can be overridden. Unless gmail is being used the default port should probably be changed.

The -to option can be a list of email addresses of any length. A call might look like:

sendMail -user [email protected] -to {[email protected] [email protected]} -subject Meow -text "Purr, purr"

If a large number of emails are being sent, depending on what is changing from one to the next, it could possibly improve efficiency to save the $msg object and reuse it.