.

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

End-To-End BlackBerry Application (Part 6)

July 15, 2008 18:01 by Jorge

In this sixth delivery of my end-to-end BlackBerry application walk-through, I will cover the following topics:

  • Creating a .NET http handler to send and receive information from the handheld application
  • Consuming the server-side business logic services from our http handler
  • Making requests from the handheld application and receiving data

While the previous articles of this series dealt with creating the Java application that will be installed on the handheld device, today I will be working on the server-side modules. Let’s take another look at our basic building blocks:

Building-Blocks1

The server-side modules consist of a .NET HTTP handler, a set of class libraries that contain the business logic and data access code, and a SQL Server database that will serve as the articles repository of our Knowledge Base application.

Creating The HTTP Handler

The mission of  the HTTP Handler is to extract the information from the HTTP requests made from the handheld, determine what type of action is required and ask the business logic layer to execute such actions. It will also append the results produced by the business logic to HTTP responses and send them to the handheld application.

In order for the handheld application and the handler to be able to talk to each other, all the commands that the handheld application can possibly send need to be defined within the handler as they were defined in the handheld:

// The commands the handheld can send us.
private const int CMD_SEARCH_ARTICLES = 1;
private const int CMD_GET_ARTICLES_BY_TAG = 2;
private const int CMD_GET_TAG_COUNTS = 3;

The keys identifying  each of the request parameters need to be defined as well:

// The request keys.
private const string KEY_COMMAND = "cmd";
private const string KEY_SEARCH_PHRASE = "sp";
private const string KEY_TAG = "tg";

KEY_SEARCH_PHRASE identifies the request parameter carrying the search phrase when a request to search the existing articles is made. KEY_TAG identifies the parameter carrying the tag name when the request is to retrieve the articles for a given tag.

Determining what to do is a matter of inspecting the request parameter marked with the KEY_COMMAND key:

string commandString = request.Form[KEY_COMMAND];
 
if (!int.TryParse(commandString, out currentCommand)) 
{
    // Bail if we don't receive a numeric command.
    return;
}
 
articlesServer = Shared.GetArticlesServer(context);
 
switch (currentCommand)
{
    case CMD_SEARCH_ARTICLES:
        string searchPhrase = request.Params[KEY_SEARCH_PHRASE];
        responseString = SearchArticles(searchPhrase);
        break;
    case CMD_GET_ARTICLES_BY_TAG:
        string tag = request.Params[KEY_TAG];
        responseString = GetArticlesForTag(tag);
        break;
    case CMD_GET_TAG_COUNTS:
        responseString = GetTagCounts();
        break;
    default:
        return;
}

Consuming The Business Logic Services

I won’t go into the details of the construction of the business logic and data access layers today, since they were covered in my End-to-end ExtJS application series. Something noteworthy, though, is the fact that these layers support storage of the articles in a file or in a SQL Server database. The code download for today’s article defaults to file-based storage, but you can run the included SQL script to install the database and point the business layer to it by changing the web application’s configuration file.

In the HTTP handler, SearchArticles(), GetArticlesForTag() and GetTagCounts() simply forward the requests to the business logic layer:

private string SearchArticles(string searchPhrase)
{
    Debug.Assert(searchPhrase != null);
    if (null == searchPhrase)
    {
        ExceptionPolicy.HandleException(
                new ArgumentNullException("searchPhrase"), 
                Shared.KB_EXCEPTION_PLCY);
    }
 
    string result = string.Empty;
 
    try
    {
        List<IArticle> articles = 
            articlesServer.GetArticlesForSearchPhrase(searchPhrase);
        if (null == articles) return 
                string.Empty;
        result = SerializeArticlesList(articles);
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
 
    return result;
}
private string GetArticlesForTag(string tag)
{
    Debug.Assert(tag != null);
    if (null == tag)
    {
        ExceptionPolicy.HandleException(
            new ArgumentNullException("tag"), 
            Shared.KB_EXCEPTION_PLCY);
    }
 
    string result = string.Empty;
 
    try
    {
 
        List<IArticle> articles = articlesServer.GetArticlesForTag(tag);
        if (null == articles) return
                string.Empty;
        result = SerializeArticlesList(articles);
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
 
    return result;
}
private string GetTagCounts()
{
    StringBuilder sb = new StringBuilder("");
 
    try
    {                
        Dictionary<string, int> tagCounts = articlesServer.GetTagCounts();
 
        if (null != tagCounts && tagCounts.Count > 0)
        {
            foreach (KeyValuePair<string, int> tagStat in tagCounts)
            {
                sb.Append(string.Format("{0}^~^{1}~^~", 
                    tagStat.Key, 
                    tagStat.Value));                       
            }
        }
 
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
    return sb.ToString();
}

After the business logic results are delivered to the handler I need to serialize the results according the formatting convention I had established when I wrote the handheld code. For example, this is the routine that converts a list of articles into a string that will be sent to the handheld as part of the HTTP response:

private string SerializeArticlesList(List<IArticle> articles)
{
    Debug.Assert(articles != null);
    if (null == articles)
    {
        ExceptionPolicy.HandleException(
            new ArgumentNullException("articles"), 
                Shared.KB_EXCEPTION_PLCY);
    }
 
    StringBuilder sb = new StringBuilder("");
    string body;
 
    foreach (IArticle article in articles)
    {
        // Decode the html characters in the body of the article.
        body = HttpUtility.HtmlDecode(HttpUtility.UrlDecode(article.Body));
        // Strip the html characters (We're using a RichTextField on the handheld,
        // which isn't capable yet of displaying html.
        body = Regex.Replace(body, @"<(.|\n)*?>", string.Empty);
 
        sb.Append(string.Format("{0}^~^{1}^~^{2}^~^{3}^~^",