ActionMailer, Attachments, and Hotmail
Last week I had the need to use ActionMailer to send email messages with attachments. As with most things Rails, doing so seemed pretty straight forward and my initial implementation appeared to go off without a hitch. My application would send the messages to an email address that I generally check using Thunderbird and each message would arrive with attachment in tow. The attachment would be named something generic like, "ATT001," would have the proper MIME type, and could be opened using an appropriate application. At some point, however, I changed to recipient address to send the email message to a Hotmail account. I checked the account using the on-line, Hotmail interface. The message was received and, in the Inbox listing, appeared to have an attachment, but when I opened the message there was no sign of the attachment at all. After a few more tests I came to the conclusion that Hotmail's failure to present the attachment was actually a failure on my part to construct the email properly in my Rails code. My code looked something like this:
def notification(applicant)
subject 'Employment Application'
recipients 'myuname@hotmail.com'
from applicant.email
body :applicant => applicant
attachment :content_type => applicant.resume_content_type,
:body => File.open(applicant.resume.path, 'rb') { |f| f.read }
end
I should mention that my platform was Rails 2.3.4 and that I was using the Paperclip plugin to upload the files to be attached to the email messages.
So, first things first, I decided to Google around a bit to see if this was a common problem. As you might guess, since I have decided to write about this experience, I really didn't find much; just one post on apidock.com. Here's a link to the post so you can read it yourself:
http://apidock.com/rails/ActionMailer/Base#673-Content-type-for-emails-with-attachments
The post essentially said that setting the content-type for the message to multipart/alternative would cause Hotmail to ignore attachments and that I should use multipart/mixed instead. Well, as you can see, I was not explicitly setting the content-type for the message (and I had only provided a single template for rendering the message). Still, I took the poster's advice and explicitly set the content-type for the message to multipart/mixed. Alas, the problem persisted.
After searching and searching the web for help and trying many variations on the code I realized that I was fast approaching my deadline for having the application done and decided I better move on and return to the problem later. Before moving on I decided that I did not like the generic names that were being assigned to the attachments and so I changed the code to ensure a more meaningful name. On a whim, I decided to try sending to the Hotmail account again and guess what! I worked! Apparently, not explicitly assigning a name to the attachment prevents Hotmail from allowing access to the attachment.
For good measure, I decided to try one more test: Gmail. It turned out to be a good decision, as when using the Gmail web interface to access an email message generate by my code, the message appeared with an empty body and two attachments. The first attachment was the intended message body and the second attachment was the expected attachment. The problem was easily rememdied by removing the line of code that set the message's content-type to multipart/mixed. My final code looked something like this:
def notification(applicant)
subject 'Employment Application'
recipients 'myuname@hotmail.com'
from applicant.email
body :applicant => applicant
attachment :content_type => applicant.resume_content_type,
:filename => "resume",
:body => File.open(applicant.resume.path, 'rb') { |f| f.read }
end
Font Preview Using CSS3
Not too long ago, I thought if I wanted to make a web site that allowed users to enter text and then see that text in various fonts, fonts that may not exist on their local computer, that I would need to embed a Flash application which in turn had the available fonts embedded in it. Today, thanks largely to http://sixrevisions.com/css/font-face-guide/, I know I can accomplish the task, at least for most browsers, using CSS and @font-face.
The first thing you will need is a page with the following features: (1) some way for the user to provide the text they want to preview, (2) some way for the user to choose the font they want to preview, and (3) some way to display the provided text using the chosen font. My page contained something similar to:
<div id="preview_container">
<div id='preview_txt'>Sample preview text</div>
</div>
<div>
Text to preview:
<input id="preview_text_input" type="text" value=""
onchange="changePreviewText('preview_text_input', 'preview_txt')" /> </div>
<div>
Font Choice<br/>
<div>
<input id="radio_font1" name="font-selector"
onclick="changePreviewFont('preview_container', 'Font1')"
type="radio" value="Font1" />
Font1
</div>
<div>
<input id="radio_font2" name="font-selector"
onclick="changePreviewFont('preview_container', 'Font2')"
type="radio" value="Font2" />
Font2
</div>
</div>
Notice that the input, with id=preview_text_input, makes use of a javascript function that changes the "inner text" of the div, with id=preview_txt, whenever the value of the input changes. I will not discuss that javascript function further here. Also notice that the two radio buttons make use of javascript function when clicked. That function looks like this:
function changePreviewFont(preview_div_id, font_name) {
var preview_div = document.getElementById(preview_div_id);
preview_div.style.fontFamily = font_name;
}
All the function does is set the font-family style for the div with id=preview_container. Specifically we set the style to either "Font1" or "Font2" depending on which radio button was clicked. And so, we have arrived at the crux of this little foray. How do we define "Font1" and "Font2." We do it with the following CSS code:
@font-face
{
font-family: Font1;
src: url('<your first eot font filename>.eot');
src: local(' '), url('<your first ttf font filename>.ttf') format('truetype');
}
@font-face
{
font-family: Font2;
src: url('<your second eot font filename>.eot');
src: local(' '), url('<your second ttf font filename>.ttf') format('truetype');
}
Of course, you will need to replace the "<>" variables with the appropriate filenames. So, obviously, the font-family element of the @font-face block defines the names we will use in setting the font-family style of the preview text div. The src elements tell CSS where to find the actual font files to use. In this case I am expecting that the font files reside in the same directory as the HTML/CSS file(s) and so I simply give the appropriate filename; however, the font files may even reside on a remote web server in which case I would access them by specifying the full URL to that font file. Furthermore, I have only accomodated Firefox and Internet Explorer and so only have two src elements. The first accomodates Internet Explorer as IE's implementation of @font-face requires font files in EOT format. The second line does two things. First, by including, "local(' ')," it ensures that the browser will not find a suitable local font file to use. Second, it accomodates Firefox by providing the location of a font file in TTF (truetype) format.
Well, that is, almost, it. The question remains where do you get the font files? I am not sure I have a great answer for you, but I will, at least, tell you what I did for the project for which I needed @font-face. First, you need to recognize that there are all sorts of sticky licensing issues surrounding the use of fonts. So be careful. In my case, I left it to the customer to ensure that they had the fonts they wanted to use properly licensed for their purposes. My customer then provided me with the TTF font files and I used the @font-face generator on font-squirrel.com to generate the EOT files I needed (along with various other formats that are needed to support other browsers). My customer provided me with one TTF file that, while it worked as a TTF, font-squirrel.com was unable to generate a @font-face package for it. I am still not sure what the impediment was. The URL for the font-squirrel @font-face generator is http://www.fontsquirrel.com/fontface/generator.
One final comment, because the browser will need to download the font files and load them for use, you may see some delay the first time you try to use a font. On my project I used the font to label the radio buttons to ensure that each font was ready for previewing when the user selected it.
A Little Bit of jQuery
I often find myself behind the curve when it comes to web application technology. There is always something new popping up I am usually hung up on discovering or working out best practices with yesterdays gizmos. Well recently I worked on a project that forced me to learn and use some newer technologies so I thought that was probably as good of place as any to start this blog.
I am sure most of you have seen dialog boxes that have been popping up (no pun intended) on web sites that are not new browser windows and that dim the current page behind the dialog. The first time I experience such a dialog box it was used as a "lightbox." The dialog presented an image and allowed me to flip through a collection of related images. Since then I have seen all sorts of content in this type of dialog box. Regardless of the content, myself and many others have come to call these dialog boxes, lightbox dialogs.
The customer for the project I mentioned earlier requested that we use a lightbox dialog to allow their customers to select an image from a set of categorized thumbnails. So, I set off to learn how to make a lightbox dialog. I was not surprised to find that there are all sorts options, but the one I settled on was offered by jQuery UI and is simply called Dialog. You can find a demonstration, and documentation, here: http://jqueryui.com/demos/dialog. I won't cover the process of setting up jQuery UI in your web site/application as the instructions provided by the aforementioned web site are pretty good, but I wanted to show just how little I had to do to create this effect.
Once I had jQuery UI set up in my web application with the necessary bits for Dialog, I simply added a form button to my page:
<input type="button" value="Choose"
onclick="javascript:showDialog('#image-picker', 825)" />
where showDialog looked like:
function showDialog(content_id, dialog_width) {
$( content_id ).dialog( { width: dialog_width, modal: true,
buttons: { Cancel: function() {
$( this ).dialog( "close" ); } }
} );
};
The function call in the showDialog function is the jQuery UI invocation. It produces a lightbox dialog that is dialog_width pixels in width and has a Cancel button that simply closes the dlalog and restores the page to its previous state. The parameter content_id specifies a div that exists on the page and that div specifies the content (other than the Cancel button) for the dialog. The content is structured and styled using HTML/CSS just as it would be if it were embedded on the page. In fact, you will need to specify, "display: none" for the div to ensure that it does not appear embedded on the page and only appears in the dialog. I placed the content div for the dialog near the top of the HTML code for my page, just before the form that contains the invoking button.
Because the content of the lightbox dialog is part of the page from which it is invoked, it is simple to affect changes on the page in response to activities that occur in the dialog. In my case, when the user clicked on an image thumbnail in the dialog, the ID for the clicked image is placed in a text input on the page (not in the dialog) and the dialog is dismissed. This was accomplished by wrapping the thumbnail images with an anchor tag:
<a href="javascript:pickAndDismiss('#image-picker', 'image_input',
'image_name')">
where pickAndDismiss looked like:
function pickAndDismiss(content_id, text_box_id, image_name) {
var input_elm = document.getElementById(text_box_id);
input_elm.value = image_name;
$( content_id ).dialog( "close" );
};
The text input (id = image_input) into which the image ID (image_name) is written does not exist in the dlalog content.
That is pretty much all there is to it. I found it easy to learn and simple to implement. My project did not demand general browser compatibility, but I did test with Firefox 3.6, Internet Explorer 7 & 8, and found that jQuery UI Dialog worked fine with all three browsers. My only complaint with jQuery UI Dialog at this point is that I needed to set the dialog width in my call to the Dialog function. While you do not need to explicitly set the width, if you do not, the width defaults to 300px rather than being driven by the content which may or may not be acceptable in your application. For me, the result was that the width of the dialog is the only bit of styling that I wanted to, but was not able to, control from my CSS.
As a final note, I should also mention that the application I have been discussing was developed using Ruby on Rails and that there was one nuance to using jQuery with Rails. There are evidently some javascript conflicts created when we include both prototype (which ships with Rails) and jQuery. To work around this your javascript inclusions should look something like this:
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'jquery-1.4.2.min', 'jquery-ui-1.8.6.custom.min' %>
<script type="text/javascript">
var $j = jQuery.noConflict();
</script>
Subsequently your jQuery calls must use the variable assigned ($j), for example:
$j( content_id ).dialog( { width: dialog_width, modal: true,
buttons: { Cancel: function() {
$j( this ).dialog( "close" ); } }
} );
Note the "j" following the dollar sign ($).


