Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Send Lotus Notes Email Using C#

4.30/5 (7 votes)
22 Aug 2012CPOL4 min read 1  
How to send email to Lotus Notes from C#.

LotusNotesWithCS/AddUsingStatement.jpg

Introduction

I had this problem at work; I needed to send a notification via Lotus Notes Email with a description of the error (ex.Message) and the name of the file that contained the error. Example: looking up values in a database that are not supplied in an XML file that I use to create a pipe delimited flat file going to another system. This would cause the flat file to not be processed; it would instead be moved to an error folder, and an event log entry would be created. Of course, this doesn't help the users, but an email would. The Internet doesn't have much in the way of C#-To-Lotus Notes, so I took some VBA samples, a few C# GUI samples, and modified them for my own needs, since what was there doesn't work for use in a Windows service. This gives the service the use of an application, and best of all, I don't have to do anything but check my email.

I also use this procedure to create an email to notify another user that a file was successfully processed and is awaiting them to import into the ERP system.

Background

What this does:

  1. Automates the email process from within a Windows service.
  2. Gives the user a brief description in the subject line. E.g.: Billing Error: File Not Processed.
  3. In the body of the email, it gives the user the file name, the error in understandable terms, and a useful tip on how to fix the problem. Case in point, some of our work orders do not have a lead tech assigned; this value is looked up in the database and is not contained in the XML file. The lack of a lead tech will cause an error to be thrown (I created several custom exceptions for this purpose, e.g.: LeadTechNotFoundException). I use this to tell the user to go into the database, add a lead tech, and then move the XML file from the error folder back into the processing folder. The service picks it up via a FileSystemWatchers and re-processes it. If they copy instead of move, I check for the file and delete it if it exists. Simple, eh?

Using the code

Set your reference to the Domino COM Object.

LotusNotesWithCS/DominoAddRef.jpg

This code can be used as is or modified. It's fully functional (at least on my systems).

C#
static void SendNotesErrorMail( string err, string file) 
{
    //Pass in file name 
    string filename = file; 
    //Pass in error message from TryCatch 
    string errMessage = err; 
    //Create new notes session 
    NotesSession _notesSession = new NotesSession(); 
    //Initialize Notes Database to null; nothing in VB. 
    NotesDatabase _notesDataBase = null; 
    //Initialize Notes Document to null; nothing in VB. 
    NotesDocument _notesDocument = null; 
    //Notes Server Name in form of: ServerName/Domain. 
    string sServerName = ConfigurationManager.AppSettings [ "ServerName" ]; 

    //Mail File is in form of: mail\\userName.nsf 
    string sMailFile = ConfigurationManager.AppSettings [ "MailFile" ]; 
    string password = ConfigurationManager.AppSettings [ "Password" ]; 
    string sSendTo = ConfigurationManager.AppSettings [ "SendTo" ]; 
    string sSubject = "Billing Error"; 
    //required for send, since it's byRef and not byVal, gets set later. 
    object oItemValue = null; 
    //use string array to CC Send 
    string[] sCopyTo = new string[4]; 
    sCopyTo [ 0 ] = 
        ConfigurationManager.AppSettings [ "Recipient0" ]; 
    sCopyTo [ 1 ] = 
        ConfigurationManager.AppSettings [ "Recipient1" ]; 
    sCopyTo [ 2 ] = 
        ConfigurationManager.AppSettings [ "Recipient2" ]; 
    sCopyTo [ 3 ] = 
        ConfigurationManager.AppSettings [ "Recipient3" ]; 
    //Initialize Notes Session 
    _notesSession.Initialize(password);

    //Get Database via server name & c:\notes\data\mailfilename.nsf 
    //if not found set to false to not create one 
    _notesDataBase = _notesSession.GetDatabase(sServerName, sMailFile, 
        false); 

    //If the database is not already open then open it. 
    if ( !_notesDataBase.IsOpen ) 
    {
        _notesDataBase.Open( );
    }

    //Create the notes document 
    _notesDocument = _notesDataBase.CreateDocument();

    //Set document type 
    _notesDocument.ReplaceItemValue(
        "Form", "Memo"); 

    //sent notes memo fields (To: CC: Bcc: Subject etc) 
    _notesDocument.ReplaceItemValue(
        "SendTo", sSendTo); 
    _notesDocument.ReplaceItemValue(
        "CopyTo", sCopyTo); 
    _notesDocument.ReplaceItemValue(
        "Subject", sSubject); 

    //Set the body of the email. This allows you to use the appendtext 
    NotesRichTextItem _richTextItem = _notesDocument.CreateRichTextItem("Body"); 

    //add lines to memo email body. the \r\n is needed for each new line. 
    _richTextItem.AppendText(
        "Error: " + errMessage + "\r\n"); 
    _richTextItem.AppendText(
        "File: " + filename + "\r\n"); 
    _richTextItem.AppendText(
        "Resolution: " + resolution + "\r\n"); 
    //send email & pass in byRef field, this case SendTo (always have this, 

    //cc or bcc may not always be there. 
    oItemValue = _notesDocument.GetItemValue( 
        "SendTo" ); 
    _notesDocument.Send(
        false, ref oItemValue); 

    //release resources. 
    _richTextItem = 
        null; 
    _notesDocument = 
        null; 
    _notesDataBase = 
        null; 
    _notesSession = 
        null; 
}

Points of Interest

This was a pain. There are a lot of VBA / Access / Excel with Lotus Notes how-to's etc. There is also a pretty nice example here from another user, with a GUI.

The changes I will make is to check a value in the app.config file and set the array size from that count. I also need to add some additional sections to the "resolution" section for my users. I may post a sample project, if I can get some time.

This is my first post here, so I hope it helps someone out.

Updates

  1. Writes the file errors to sql server for tracking purposes, captures the filename, datetime, error and so on.
  2. It creates and sends an email on a per file error/success basis.
  3. It sends a copy of all the email to the "primary" email address. There is a record of every file error and reason along with every report/workorder sent to a customer(s).
  4. I converted a manual process I used for testing into a windows service, which uses a directorymonitor to catch newly created files dropped into a folder and processes them on a FIFO basis.
  5. I left my errors commented out so you can see what was correct and what wasn't (at least for my usage)
  6. I use the Configuration.Manager.AppSettings variables b/c it's easier to stop a service, change a line than it is to edit code, recompile, test and deploy. This way you just stop the service, change the app.config file, save it and start the service. Works very well when the network guys change mail servers on you.
  7. At the very end is a sample of the App.Config file referenced in the code, for those of you who don't know how to use it.

Add the using System.net.mail to the header section of your class.

C#
public static void CreateSuccessMessage()
{
string mailServer = ConfigurationManager.AppSettings["ServerName"];
string SendTo = ConfigurationManager.AppSettings["BaanSendTo"];
string SendFrom = ConfigurationManager.AppSettings["SendFrom"];
MailMessage message = new MailMessage(SendFrom, SendTo);
message.Subject = "WorkOrder/Contract Import File Ready.";
message.Body = "File Ready To Process";

SmtpClient client = new SmtpClient(mailServer);
// Credentials are necessary if the server requires the client 
// to authenticate before it will send e-mail on the client's behalf.
client.UseDefaultCredentials = false;
client.Send(message);
}

public static void SendSmtpMessage(int messageType, string workContract, string err, string fileName)
{
string mailServer = ConfigurationManager.AppSettings["ServerName"];
string SendFrom = ConfigurationManager.AppSettings["SendFrom"];
MailMessage message = new MailMessage();

if (messageType == 0)
{
//send success message

//string SendTo = ConfigurationManager.AppSettings["BaanSendTo"];
//string CopyTo = ConfigurationManager.AppSettings["Recipient3"];
//message = new MailMessage(SendFrom, SendTo + "," + CopyTo);
//message.Subject = System.Environment.MachineName + ": WorkOrder/Contract Baan Import File Ready.";
//message.Body = fileName + " Is Ready To Process";
//message.Body = "Originating Server: " + System.Environment.MachineName;
//message.Body += System.Environment.NewLine;

}
else
{
//string strSQL = "INSERT INTO tblXmlOutErrors (ErrorDate, ErrorMessage, filename, Server, WorkOrderNumber) " +
// "Values (" + DateTime.Now + ", " + err + ", " + fileName + ", " + System.Environment.MachineName +", " + workContract + ")"; //ContractNumber + ", " + WorkOrderNumber + ")"

string strSQL = "pS1FxXmlOutErrors_Insert ";
strSQL = strSQL + "'" + DateTime.Now + "'," + "'" + err + "'," + "'" + fileName + "'," + "'" + System.Environment.MachineName + "'," + "'" + workContract + "'";

string sqlConnectionString = ConfigurationManager.ConnectionStrings["AppConfigConnectionNameHere"].ConnectionString;

SqlConnection db_conn = new SqlConnection(sqlConnectionString);

SqlCommand ErrorInsertSqlCommand = new SqlCommand();

Trace.WriteLine(strSQL);

ErrorInsertSqlCommand.Connection = db_conn;
ErrorInsertSqlCommand.CommandText = strSQL;
ErrorInsertSqlCommand.CommandType = CommandType.Text;

db_conn.Open();

ErrorInsertSqlCommand.ExecuteNonQuery();

db_conn.Close();

//Send error Message.
string SendTo = ConfigurationManager.AppSettings["SendTo"];
string CopyTo = ConfigurationManager.AppSettings["Recipient1"];

message = new MailMessage(SendFrom, SendTo + "," + CopyTo);
message.Subject = System.Environment.MachineName + ": WorkOrder/Contract File Error.";
message.Body = "Originating Server: " + System.Environment.MachineName;
message.Body += System.Environment.NewLine;
message.Body += "WorkOrder/Contract Number: " + workContract;
message.Body += System.Environment.NewLine;
message.Body += "File That Caused The Error: " + fileName;
message.Body += System.Environment.NewLine;
message.Body += "The Error Message is: " + err;
message.Body += System.Environment.NewLine;
message.Body += "Suggested Action: Go Into System, Correct Values, Save And Re-Export";
}

SmtpClient client = new SmtpClient(mailServer);
// Credentials are necessary if the server requires the client 
// to authenticate before it will send e-mail on the client's behalf.
client.UseDefaultCredentials = false;
client.Send(message);
}

public static void SendPdfWorkOrderCompletedEmail(string workContract, string ReportFileName, string strEmailTo, string strMailFrom)
{
string mailServer = ConfigurationManager.AppSettings["ServerName"];
string SendFrom = strMailFrom;
string SendTo = strEmailTo.Replace(";", ",");
SendTo = SendTo + ", hardcodedemainaddresshere";
string recptnts = SendTo.Replace(".com", "");
recptnts = recptnts.Replace(".net", "");
recptnts = recptnts.Replace(".org", "");
recptnts = recptnts.Replace(".biz", "");

MailMessage message = new MailMessage();
message = new MailMessage(SendFrom, SendTo);
message.Subject = "SourceOne Workorder " + workContract + " completed.";
message.Body = "To " + recptnts + ":";
message.Body += System.Environment.NewLine;
message.Body += System.Environment.NewLine;
message.Body += " Your e-mail address(es) are listed on this service event to receive an electronic copy of the Workorder.";
message.Body += System.Environment.NewLine;
message.Body += "The details of this event are included in the attached PDF file.";
message.Body += System.Environment.NewLine;
message.Body += "If you have received this e-mail in error, please reply to have your address removed from future Workorders.";
message.Body += System.Environment.NewLine;
message.Body += "Thank you for your Business.";
message.Body += System.Environment.NewLine;
message.Body += System.Environment.NewLine;

message.Attachments.Add(new Attachment(ReportFileName));

SmtpClient client = new SmtpClient(mailServer);

client.UseDefaultCredentials = false;
client.Send(message);

string strSQL = "StoredProcedureNameToUpdateCustomBoolField_pdfEmailSent ";
strSQL = strSQL + "'" + workContract + "'";

string sqlConnectionString = ConfigurationManager.ConnectionStrings["NameHere"].ConnectionString;

SqlConnection db_conn = new SqlConnection(sqlConnectionString);

SqlCommand PdfSentUpdateSqlCommand = new SqlCommand();

Trace.WriteLine(strSQL);

PdfSentUpdateSqlCommand.Connection = db_conn;
PdfSentUpdateSqlCommand.CommandText = strSQL;
PdfSentUpdateSqlCommand.CommandType = CommandType.Text;

db_conn.Open();

PdfSentUpdateSqlCommand.ExecuteNonQuery();

db_conn.Close();

//if (File.Exists(ReportFileName))
//{
// File.Replace(ReportFileName, ReportFileName,"",true);
// //File.Delete(ReportFileName);
//}
}

public static void SendSmtpBillingFileIssuesMessage()
{
string mailServer = ConfigurationManager.AppSettings["ServerName"];
string SendFrom = ConfigurationManager.AppSettings["SendFrom"];
string SendTo = ConfigurationManager.AppSettings["Recipient5"];

MailMessage message = new MailMessage(SendFrom, SendTo);
message.Subject = "Flat Files To ERP System Building Up.";
message.Body = "Check that the File Transfer Service Is Running, If Not Start It.";
message.Body += System.Environment.NewLine;
message.Body += "Service Runs Every " + ConfigurationManager.AppSettings["ElapsedTime"];
message.Body += System.Environment.NewLine;
message.Body += "Check it again after that time frame, or wait for another mail message.";

SmtpClient client = new SmtpClient(mailServer);
// Credentials are necessary if the server requires the client 
// to authenticate before it will send e-mail on the client's behalf.
client.UseDefaultCredentials = false;
client.Send(message);
}

AppConfig example: in the first set of quotes is the variable refd in code, in the second set is the value.

<maillistadd key="FileInPath" value="C:\Folder\subFolder" />

<!-- The File Transfer Timer In Minutes-->
 <add key="ElapsedTime" value="5"/>
    <add key="ServerName" value="mail.somedomain.com"/>
    <add key="SendTo" value="CommaSeperatedInHouseErrorlist"/>
    <add key="SendFrom" value="mainemail@somedomain.com"/>
    <add key="2nd email SendTo type" value="emaillist"/>
    <add key="Recipient0" value="emaillist"/>
    <add key="Recipient1" value="maillist"/>
    <add key="Recipient2" value="maillist"/>
    <add key="Recipient3" value="maillist"/>
    <add key="Recipient4" value="maillist"/>
    <add key="Recipient5" value="maillist"/> 
    </appSettings>
    <connectionStrings>
        <add name="ConnectionVariableName" connectionString="Data Source=ServerName;Initial Catalog=databaseName;Persist Security Info=True;User ID=UserID;Password=PW;MultipleActiveResultSets=True;"/>
    </connectionStrings>

There you have it. Works very very very well for sending emails to customers, errors to internal departments, notifications to internal departments, and logging errors and issues in a datatable and reporting it.

Hope it helps.

Have a great day!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)