Monthly Archives: September 2011

Forums back up


For the two or three of you out there who recently tried reaching my forum, it is now back up and running. Enjoy!

Railo installer issues on Arch Linux


The Railo installer does a great job across multiple operating systems but it is not completely infallible (although it does come awfully close). The installer will complete, but there are two extra steps you will need to take to get things up and running smoothly on Arch Linux.

First, fire up your favorite editor and open up /opt/railo/tomcat/conf/server.xml and scroll down until you find the HTTP connector block. You will see something along the lines of “@@tomcatport@@” listed where the port should be. Replace this value with whichever port you want Tomcat listening on.

Next we need to move the railo_ctl file from /opt/railo/ to /etc/rc.d/, this is the folder that Arch Linux uses for its daemon services instead of /etc/init.d/ like Debian and RHEL systems use. Once the file is in there, chmod 0755 /etc/rc.d/railo_ctl to set the permissions on the file.

Finally, if you want Railo to startup automatically on boot there is one final modification to make. With your favorite editor open up /etc/rc.conf and add railo_ctl to the DAEMONS line and it will now start when you boot your machine.  You should now be ready to start Railo up, just sudo /etc/rc.d/railo_ctl start and you should be in business.

cf_sesmail custom tag for Railo


Lately I have been using Amazon’s Simple Email Service quite a bit. I use the AmazonSES component for a few clients, but it still is not quite as natural as using a cfmail tag.  Running PostFix to relay messages through SES is not hard to setup, but it is a little overkill if you just need to use it from ColdFusion. With these things in mind, I remembered the post Todd Rafferty wrote about writing a cfc custom tag. I thought it would be pretty cool to write a custom tag to allow you to send an email through SES with the familiar feel of cfmail. If you would like to check it out, it is pretty easy to setup.

sesmail.cfc 
component {
/*
* Project: sesmail
* Author : Robert Zehnder
* Date   : 9/2/2011
* Purpose: cfmail-like implementation to make it easier to send emails through Amazon Simple Email Service
*/
 this.metaData.attributeType = "fixed";
 this.metaData.attributes = {
  from        : { required: true, type: "string" },
  to          : { required: true, type: "string" },
  cc          : { required: false, type: "string", default: "" },
  bcc         : { required: false, type: "string", default: "" },
  subject     : { required: true, type: "string" },
  mailerID    : { required: false, type: "string", default: "cfmailses" },
  endPoint    : { required: false, type: "string", default: "" },
  credentials : { required: true, type: "string" },
  name        : { required: false, type: "string", default: "sesResults" }
 };

 public void function init(required boolean hasEndTag, any parent) {

 }

 public boolean function onStartTag(struct attributes, struct caller) {
  return true;
 }

 public boolean function onEndTag(struct attributes, struct caller) {
  var results = {};
  var awsCredentials = createObject("java", "java.io.File").init(attributes.credentials);
  var creds = createObject("java", "com.amazonaws.auth.PropertiesCredentials").init(awsCredentials);
  var emailService = createObject("java", "com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient").init(creds);
  var props = createObject("java", "java.util.Properties");
  var verifyRequest = createObject("java", "com.amazonaws.services.simpleemail.model.VerifyEmailAddressRequest").withEmailAddress(attributes.from);
  var sendHeaders = { "User-Agent" : attributes.mailerID };

  // Set properties for establishing connection
  props.setProperty("mail.transport.protocol", "aws");
  props.setProperty("mail.aws.user", creds.getAWSAccessKeyId());
  props.setProperty("mail.aws.password", creds.getAWSSecretKey());

  // Send email message
  var mailSession = createObject("java", "javax.mail.Session").getInstance(props);
  var mailTransport = createObject("java", "com.amazonaws.services.simpleemail.AWSJavaMailTransport").init(mailSession, JavaCast("null", 0));
  var messageObj = createObject("java", "javax.mail.internet.MimeMessage").init(mailSession);
  var messageRecipientType = createObject("java", "javax.mail.Message$RecipientType");
  var messageFrom = createObject("java", "javax.mail.internet.InternetAddress").init(attributes.from);
  var messageTo = listToArray(attributes.to);
  var messageCC = listToArray(attributes.cc);
  var messageBCC = listToArray(attributes.bcc);
  var messageSubject = attributes.subject;
  var messageBody = arguments.generatedContent;
  var verified = arrayToList(emailService.ListVerifiedEmailAddresses().getVerifiedEmailAddresses()).contains(attributes.from);
  var i = 0;

  try {

   // Is the sender verified
   if(!verified){
    var verifyRequest = createObject("java", "com.amazonaws.services.simpleemail.model.VerifyEmailAddressRequest").withEmailAddress(attributes.from);
    try{
     emailService.verifyEmailAddress(verifyRequest);
    }
    catch (any e){
    }
    throw("Email address has not been validated.  Please check the email on account " & attributes.from & " to complete validation.");
   }

   mailTransport.connect();

   messageObj.setFrom(messageFrom);
   for(i = 1; i <= arrayLen(messageTo); i++){
    messageObj.addRecipient(messageRecipientType.TO, createObject("java", "javax.mail.internet.InternetAddress").init(trim(messageTo[i])));
   }

   if(arrayLen(messageCC)){
    for(i = 1; i <= arrayLen(messageCC); i++){
     messageObj.addRecipient(messageRecipientType.CC, createObject("java", "javax.mail.internet.InternetAddress").init(trim(messageCC[i])));
    }
   }

   if(arrayLen(messageBCC)){
    for(i = 1; i <= arrayLen(messageBCC); i++){
     messageObj.addRecipient(messageRecipientType.BCC, createObject("java", "javax.mail.internet.InternetAddress").init(trim(messageBCC[i])));
    }
   }

   if(len(structKeyList(sendHeaders))){
    for(i in sendHeaders){
     messageObj.addHeader(i, sendHeaders[i]);
    }
   }

   messageObj.setSubject(messageSubject);
   messageObj.setContent(messageBody, "text/html");
   messageObj.saveChanges();

   mailTransport.sendMessage(messageObj, JavaCast("null", 0));

   mailTransport.close();

  }
  catch (Any e){
   throw("Error sending message.");
  }
  return false;
 }

}

Now we can send mail through the SES gateway like this:

<cf_sesmail from="user@domain" to="other@domain" subject="subject" credentials="/path/to/awscredentials.properties">
Hello from cf_sesmail!
</cf_sesmail>

It is self-explanatory.  You supply the basics such as the from address, to address and subject. Instead of passing a user name and password for authentication, you pass the full path to your awscredentials.properties file and the tag takes care of the rest. The code is still a little rough around the edges but it is usable. I will get something up on github soon.

Here is a link to the version of the AWS SDK I am using for development. It is a little dated, but it works perfectly with Railo without requiring you to update any additional jars in your installation. Just extact this file and place the sdk jar into your Railo classpath. For Linux systems, this will most likely be /opt/railo/lib and you should be good to go. If you want to really integrate it into your web context you can copy the component into your WEB-INF/railo/library/tags/ folder, this will allow you to use the custom tag just as if it was a built in function (i.e., <cfsesmail ..></cfsesmail>).

Updated 9/4/2011:
Project is now hosted on github here: https://github.com/robertz/cf_sesmail