.

How to Embed Images in the Body of an Email Message

October 4, 2008 00:05 by Jorge

Another very simple C# sample based on a mail merge application I have been working on. This time I would like to show you how to use the System.Net.Mail facilities to programmatically embed images in the html body of an email.

public static void SendMessage(string server, 
    string from, string to, string cc, string bcc,
    string subject, string body, List<string> attachments,
    string[] embeddedFiles)
{
 
    
    MailMessage message = new MailMessage(from, to);
 
    message.Subject = subject;
    
    string[] ccArray = cc.Split(';');
    if (ccArray.Length > 0)
    {
        foreach (string address in ccArray)
        {
            if (address.Length > 0)
            {
                message.CC.Add(new MailAddress(address));
            }
        }
    }
 
    string[] bccArray = bcc.Split(';');                
    if (bccArray.Length > 0)
    {
        foreach (string address in bccArray)
        {
            if (address.Length > 0)
            {
                message.Bcc.Add(new MailAddress(address));
            }
        }
    }
 
    message.IsBodyHtml = true;
 
    if (null != embeddedFiles && embeddedFiles.Length > 0)
    {
        foreach (string filePath in embeddedFiles)
        {
            string fileName = Path.GetFileName(filePath);
            body = body.Replace(fileName, "cid:" + fileName);
        }
        AlternateView view = AlternateView.CreateAlternateViewFromString(body,
            null,MediaTypeNames.Text.Html);
        foreach (string filePath in embeddedFiles) {
            LinkedResource res = new LinkedResource(filePath);
            res.ContentId = Path.GetFileName(filePath);
            view.LinkedResources.Add(res);
            
        }
        message.AlternateViews.Add(view);
    } else {
        message.Body = body;
    }
 
    foreach (string file in attachments) {
        Attachment data = new Attachment(file);
        message.Attachments.Add(data);
    }
    
    SmtpClient client = new SmtpClient(server);
    client.Credentials = CredentialCache.DefaultNetworkCredentials;
    client.Send(message);
   
}

The trick here consists in creating an AlternateView instance for the body of the email and adding the images to this view via LinkedResource instances. Also, note how the paths to the original images inside de html body are replaced with unique identifiers that map to their embedded siblings.

More details on this approach can be found here.

Actions: E-mail | Permalink | Comments (0) | Trackback

Programmatically Accessing Mail Merge Fields in MS Word Documents

October 3, 2008 21:33 by Jorge

I have been working on a mail merge application that will allow for sending messages from a desktop computer by connecting directly to an SMTP server and not using the installed email client.

Based on this application’s code, this simple C# example shows how to programmatically replace a mail merge field in a Microsoft Word document with a desired value.

using Word = Microsoft.Office.Interop.Word;
 
...
 
public static void ReplaceMailMergeField(string msWordFileName, 
    string mailMergeFieldName, string mailMergeFieldDesiredValue)
{          
    object docName = msWordFileName;
    object missing = Missing.Value;
    Word.MailMerge mailMerge;
    Word._Document doc;
 
    Word.Application app = new Word.Application();
    // Hide MS Word's window.
    app.Visible = false;
 
    doc = app.Documents.Open(ref docName,
        ref missing, ref missing, ref missing, ref missing, 
        ref missing, ref missing, ref missing, ref missing,
        ref missing, ref missing, ref missing, ref missing, 
        ref missing, ref missing, ref missing);
 
    mailMerge = doc.MailMerge;
 
    // Try to find the field name.
    foreach (Word.MailMergeField f in mailMerge.Fields)
    {
        // Assuming the field code is: MERGEFIELD  "mailMergeFieldName"
        if (f.Code.Text.IndexOf("MERGEFIELD  \"" + mailMergeFieldName +"\"") > -1)
        {
            f.Select();
           // Replace selected field with supplied value.
            app.Selection.TypeText(mailMergeFieldDesiredValue);
        }
    }
 
    // Save changes and close MS Word.
    object saveChanges = Word.WdSaveOptions.wdSaveChanges;
    doc.Close(ref saveChanges, ref missing, ref missing);
    app.Quit(ref missing, ref missing, ref missing);
    
}

I hope you find this sample helpful.

Actions: E-mail | Permalink | Comments (0) | Trackback

Optimized HTTP Handling for Your BlackBerry Java Application

September 28, 2008 10:00 by Jorge

In this post I’m going to explore some examples of the approaches to reading HTTP responses in your BlackBerry  Java application and how they can impact the application’s performance.

I realize that the performance of your HTTP-handling routines might not impose critical limitations to your application. But if you are considering ways to optimize these routines, I encourage you not only to take a look at these approaches, but also measure their performance characteristics in the context of your application.

The first approach, which I have successfully used in a commercial application, consists of reading the contents of the HTTP response one character at a time. Although slow, this approach is attractive because it is simple and does not require any HTTP-specific behavior from your code:

StreamConnection c = null;
InputStream s = null;
try {
    c = (StreamConnection)Connector.open(url);
    s = c.openInputStream();
    int ch;
    StringBuffer response = new StringBuffer();
    while ((ch = s.read()) != -1) {
        response.append((char)i);
    }
} finally {
    if (s != null)
        s.close();
    if (c != null)
        c.close();
}

Reading the response data in bulk is a way to gain efficiency. However, this code relies on the underlying connection being able to provide the length of the response:

ContentConnection c = null;
DataInputStream dis = null;
try {
    c = (ContentConnection)Connector.open(url);
    int len = (int)c.getLength();
    dis = c.openDataInputStream();
    if (len > 0) {
        byte[] data = new byte[len];
        dis.readFully(data);
    } else {
        int ch;
        while ((ch = dis.read()) != -1) {
            ...
        }
    }
} finally {
    if (dis != null)
        dis.close();
    if (c != null)
        c.close();
}

A version of the previous approach that I use in my KnowledgeBase application is this:

HttpConnection c = null;
InputStream in = null;
String response = null;
 
try {    
    c = (HttpConnection)Connector.open(url)
    in = c.openInputStream();                         
    int len = (int)c.getLength();
 
    if (len > 0) {
      int actual = 0;
      int bytesread = 0 ;
      byte[] data = new byte[len];
      while ((bytesread != len) && (actual != -1)) {
        actual = in.read(data, bytesread, len - bytesread);
        bytesread += actual;
      }
      response = new String(data);
    } 
}

While the methods above produce a byte array and thus require a parsing or conversion step – omitted from the sample code – in order to deserialize the data, if your application has intimate knowledge of the response’s contents, you can use specialized methods of the DataInputStream class to read and deserialize the different values in the response in one step:

HttpConnection c = null;
DataInputStream is = null;
int rc;
 
try {
    c = (HttpConnection)Connector.open(url);
 
    rc = c.getResponseCode();
    if (rc != HttpConnection.HTTP_OK) {
        throw new IOException("HTTP response code: " + rc);
    }
 
    is = (DataInputStream)c.openInputStream();
 
    String lastName = i.readUTF();
    String firstName = i.readUTF();
    int numberOfOrders = i.readInt();
    boolean isActive= i.readBoolean();
    
    
} catch (ClassCastException e) {
    throw new IllegalArgumentException("Not an HTTP URL");
} finally {
    if (is != null)
        is.close();
    if (c != null)
        c.close();
}

As you can see, the performance gains have a cost in the amount of complexity of your code and the knowledge of the response contents that your application should have. You will find that this is true for the approaches above as well as other approaches that exist. When deciding on one, consider the tradeoffs and always measure your gains before making a decision.

Actions: E-mail | Permalink | Comments (0) | Trackback