Thursday 26 November 2009

Lift: Sending mail through Google Mail

I was trying to get my Lift web application to send out some mail through a Gmail account. I'm rusty with Java Mail so this took longer than it should have, so here's the code for anyone else it helps. The first big of code is just a bit of code to insert into the Boot class. I've put it in a separate method just to keep this code together, then I call it straight from the boot method.

import javax.mail.{PasswordAuthentication, Authenticator}

  private def setupMailerForGmail() {
    // Set up mailing to mail through Gmail account
    System.setProperty("mail.smtp.starttls.enable", "true")
    System.setProperty("mail.smtp.ssl.enable", "true")
    System.setProperty("mail.smtp.host", "smtp.gmail.com")
    System.setProperty("mail.smtp.auth", "true")

    // Turn on display of emailing processing logs by setting this property...
    //System.setProperty("mail.debug", "true")

    Mailer.authenticator = Full(new Authenticator {
      override def getPasswordAuthentication =
        new PasswordAuthentication("accountname…@gmail.com", "password…")
    })

  }

To send an email you can use something as short as:

import net.liftweb.util.Mailer.{To, From, PlainMailBodyType, Subject}
import net.liftweb.util.Mailer
…
    Mailer.sendMail(From("accountname…@gmail.com"), Subject("Just a test"),
      List(PlainMailBodyType("The body of the test message"), To("recipient_email_address…")) : _*)

Once this is working it's relatively straightforward to work out how to do XHTML mails and send to multiple recipients, etc.

The one bit of code that helped me the most was setting the mail.debug system property which caused the Java Mail code to output a trace of the mail sending process and allowed me to spot that I had failed to enable SSL.

Pragmatic Scala: Parsing columns from plain text

A few days ago I was preparing for a meeting and I thought I'd print out a list of all the attendees from the Eventbrite event details.

When I looked at the list I saw that it seemed to be in no particular order and didn't print very well so I thought, "I wonder if I could copy and paste this into a spreadsheet and sort it by surname". Unfortunately each entry had one or two lines and variable information in it and was delimited by spaces and commas.

Then I thought, hmm, I could process this quickly with a bit of Scala and pattern matching.

There's nothing clever here, but for me it's quite significant that the effort involved in writing this code was so low that I was able to use Scala to solve this problem there and then and it worked seamlessly. I've posted it here because there are too few simple examples of Scala lying around the web for people to get started with.

So here's the code if you're interested…

#!/bin/sh
exec scala "$0" "$@"
!#

import java.io.File
import scala.io.Source

val source = Source.fromFile(new File("Attendees.txt"))
val lines = source.getLines.trim
lines.foreach( line => {
val (details, presentation) = line.split("\t").toList match {
  case List(d) => (d,"")
  case List(d,p) => (d,p)
}
val (name, position, organisation) = details.split(", ").toList match {
  case List(n) => (n,"","")
  case List(n,c) => (n,"",c)
  case List(n,p,c) => (n,p,c)
  case List(n,p,d,c) => (n,p+ ", "+d,c)
}
val (first, middle, last) = name.split(" ").toList match {
  case List(f) => (f,"","")
  case List(f,l) => (f,"",l)
  case List(f,m,l) => (f,m,l)
}

println(List(first,middle,last,position,organisation,presentation).mkString("\t"))
})

It was parsing lines of text which looked roughly like this:

Firstname [Middlename] Surname, [[Position, [Department ,]]Company][\t Presentation]
(e.g. bits in square brackets were optional).

For those unfamiliar with Scala, the first three lines just allow the code to be run as a script on the command line just like any shell script. Then the lines.foreach( line => code just loops through each line of code setting line equal to that line. The nice bit is the matching parts which assign values to multiple values at once so:

 val (details, presentation) = line.split("\t").toList match {
  case List(d) => (d,"")
  case List(d,p) => (d,p)
}
effectively says:
  • Assign to the variables: details and presentation at once, the value of the following expression.
  • Take the line and convert it to an array of Strings by separating it at every tab character, then convert the array to a List.
  • Match the List to one of two patterns:
  • If it matches the pattern of a List with one entry then assign the value of that entry to d and return the thing on the right hand side of the =>. In this case it is a tuple (pair of values): d and an empty String.
  • If it matches the pattern of a List with two entries then assign d to the first and p to the second and then return them both as a tuple.

So, at the end we have details set to everything before the tab and presentation set to everything after the tab or an empty string if there was no tab.

However, if there are two or more tabs then none of the patterns match so the program creates a runtime error which is great because we know that the program is either doing what it was meant to or not.

Wednesday 13 May 2009

An end to restart problems on Mac OS 10.5.7

I've been running on 10.5.7 for a little while before the official release and having problems with the machine refusing to shutdown properly. Yesterday I ran across a discussion board support comment that recommended removing items from your home directory ~/Library/Plug-ins directory and removing the top level /Library/Preferences/com.apple.loginwindow.plist file.
I don't know which one solved the problem because I couldn't be bothered doing one at a time, but I ended up removing an old DiskImages directory in my plug-ins which had a VirtualPCDiskImagePlugin.bundle in it that seemed to be creating errors in my log at startup, and I removed the loginwindow.plist file. Now everything seems to be working smoothly again!
This post marks a return to blogger, because I've decide to blog again from time to time and it's the easiest option for me right now!
 
Google Analytics Alternative