On this page:
  • Even more awesome LotusScript mail merge for Lotus Notes + Microsoft Excel
  • Analyzing my Lotus Notes sent mail since January 2011
  • Setting e-mail expectations: Roughly once a week

Even more awesome LotusScript mail merge for Lotus Notes + Microsoft Excel

UPDATE: May 20, 2011 – David Turner has shared his excellent improvements. Check them out!

UPDATE: May 28, 2010 – fixed errors caused by default Option Declare. Thanks to Lisa Harnett for the feedback!
UPDATE: Oct 19, 2010 – fixed Quit(). Thanks to Vance for the feedback! Also, clarified tokens.

Based on the feedback on my Lotus Notes mail merge from a Microsoft Excel spreadsheet (2009), I’ve refined my merge script to make it more awesome. How is it more awesome?

  • Prompts you for drafting or sending
  • Saves sent messages
  • Allows you to customize the subject
  • Uses [ ] instead of < and > for built-in tokens ([to], [cc], [subject]) for less HTML confusion in blog posts and replies
  • Displays number of sent messages and errors
  • Closes the Microsoft Excel spreadsheet afterwards

The search-and-replace tokens are defined in the first row of your Microsoft Excel spreadsheet. The script searches for them in the message body, replaces them with the appropriate values from the current row, and either saves the message as the draft or sends the message. There are a few built-in tokens for this script ([to], [cc], [subject]) – these are case-sensitive, so enter them exactly like that. All the other tokens are up to you, so you could use FOO and BAR as search-and-replace tokens if you want.

Tokens are replaced only in the message body. If you want a variable subject line, use a formula to calculate the subject in a column with the [subject] header.

As always, test your mail merges with a small list before using it for your entire list. Create an agent and call it something like “Mail merge”. Edit the agent and set the type to LotusScript. In the (Declarations) section, add

%Include "lsconst.lss"

In the “Initialize” section, put in:

Sub Initialize
	'Mail merge script by Sacha Chua ([email protected])

	Dim ws As NotesUIWorkspace
	Set ws = New NotesUIWorkspace
	Dim sendTypes(1) As String
	Dim sendValue As String
	Dim errorCount As Integer
	errorCount = 0
	sendTypes(0) = "Draft messages without sending"
	sendTypes(1) = "Send messages"
	sendValue = ws.Prompt(PROMPT_OKCANCELLIST, "Sending options", "What would you like to do?", "", sendTypes)
	If (sendValue = "") Then
		Exit Sub
	End If

	Dim fileName As String
	Dim strXLFilename As String
	'Prompt for the filename - should be a Microsoft Excel file with columns, where the first row of each column
	'is a token that will be used when replacing text in the body of the message
	'Special tokens: [to], [cc], [subject] set the appropriate fields
	'Make sure the first column does not have any blank cells
	fileName$ = ws.Prompt(12, "Select file", "3")
	If fileName$ = "" Then
		Exit Sub   'Cancel was pressed
	End If
	strXLFilename = fileName$
	Dim s As New NotesSession
	Dim uidoc As NotesUIDocument
	Dim partno As String
	Dim db As NotesDatabase
	Dim view As NotesView
	Dim doc As NotesDocument
	Dim collection As NotesDocumentCollection
	Dim memo As NotesDocument
	Dim body As NotesRichTextItem
	Dim newBody As NotesRichTextItem
	Dim range As NotesRichTextRange
	Dim count As Integer

	Set db = s.CurrentDatabase
	Set collection = db.UnprocessedDocuments
	Set memo = collection.getFirstDocument()

	Dim varXLFile As variant
	'Get data from the spreadsheet
	Set varXLFile = CreateObject("Excel.Application")
	varXLFile.Visible = False
	Dim varXLWorkbook As variant
	Set varXLWorkbook = Nothing
	varXLFile.Workbooks.Open strXLFilename
	Set varXLWorkbook = varXLFile.ActiveWorkbook
	Dim varXLSheet As variant
	Set varXLSheet = varXLWorkbook.ActiveSheet

	Dim lngRow As Integer
	Dim columnNo As Integer
	Dim token As String
	Dim value As string
	lngRow = 2
	Dim maildoc As NotesDocument
	While (Not (varXLSheet.Cells(lngRow, 1).Value = ""))
		'Fill in the template
		Dim subject As string
		subject = memo.Subject(0)
		Set body = memo.GetFirstItem("Body")

		'Compose message
		Set maildoc = New NotesDocument(db)
		Set maildoc= db.CreateDocument()
		maildoc.Form = "Memo"
		maildoc.Subject = subject
		Set newBody = maildoc.CreateRichTextItem("Body")
		Call newBody.appendRTItem(body)
		Set range = newBody.CreateRange			

		'Count the number of fields
		'Look up tokens from the column headings and replace them
		columnNo = 1
		While Not(varXLSheet.Cells(1, columnNo).Value = "")
			token = varXLSheet.Cells(1, columnNo).Value
			value = varXLSheet.Cells(lngRow, columnNo).Value
			count = range.FindAndReplace(token, value, 16)
			If (token = "[to]") Then
				maildoc.SendTo = value
			End If
			If (token = "[cc]") Then
				maildoc.CopyTo = value
			End If
			If (token = "[subject]") Then
				maildoc.Subject = value
			End If
			columnNo = columnNo + 1
		On Error GoTo save
		If (sendValue = sendTypes(0)) Then
			Call maildoc.Save(True, False)
			maildoc.SaveMessageOnSend = True
			maildoc.PostedDate = Now()
			Call maildoc.Send(False)
			Call maildoc.Save(True, True)
		End If
		GoTo nextrow
		MessageBox("Error processing " + maildoc.sendTo)
		errorCount = errorCount + 1
		Resume Next
		lngRow = lngRow + 1
	If (sendValue = sendTypes(0)) Then
		MsgBox "Drafted " & (lngRow - errorCount - 2) & " message(s). Errors: " & errorCount
		MsgBox "Sent " & (lngRow - errorCount - 2) & " message(s). Errors: " & errorCount
	End If
	Call varXLFile.Quit()
End Sub

Analyzing my Lotus Notes sent mail since January 2011

Today is my penultimate day at IBM! Having successfully turned my projects over to another developer (hooray for the habit of organizing project-related files in Lotus Connections Activities), I’ve been focusing on getting things ready for the traditional goodbye e-mail, which I plan to send tomorrow.

I dug around in the Lotus Connections Profiles API to see if I could get a list of my contacts’ e-mail addresses. I fixed a small bug in the feed exporter of the Community Toolkit (w4.ibm.com/community for people in the IBM intranet) and exported my contacts, giving me a list of 530 IBMers who had accepted or sent me an invitation to connect.

Not everyone participates in that Web 2.0 network, though, so I wanted to analyze my sent mail to identify other people to whom I should send a note. I couldn’t find a neat LotusScript to do the job, and I couldn’t get the NSF to EML or mbox converter to work. Because I didn’t need all the information, just the recipients, subjects, and times, I wrote my own script (included at the end of this blog post).

I used the script to summarize the messages in my sent mail folder, and crunched the numbers using PivotTables in Microsoft Excel. I worked with monthly batches so that it was easier to find and fix errors. I decided to analyze all the mail going back to the beginning of last year in order to identify the people I mailed the most frequently, and to come up with some easy statistics as well.


Spiky around project starts/ends, I’d guess.


I wanted to see which roles I tended to e-mail often, so I categorized each recipient with their role. I distinguished between people I’d worked with directly on projects (coworkers) and people who worked with IBM but with whom I didn’t work on a project (colleagues). The numbers below count individual recipients.


Number of people

Number of individual
e-mails sent

Average e-mails sent
per person

colleague 407 827 2.0
coworker 50 562 11.2
client 21 387 18.4
manager 4 109 27.3
partner 9 51 5.7
system 9 21 2.3
other 8 11 1.4
self 1 5 5.0
Grand Total 509 1973 3.9

As it turns out, I sent a lot of mail to a lot of people throughout IBM, mostly in response to questions about Lotus Connections, Idea Labs, or collaboration tools.

Now I can sort my summarized data to see whom I e-mailed the most often, and add more names to my don’t-forget-to-say-goodbye list. If all goes well, I might even be able to use that mail merge script. =)

The following agent processes selected messages and creates a table with one row per recipient, e-mailing the results to the specified mail address. It seems to choke on calendar entries and other weird documents, but if you go through your sent mail box in batches (Search This View by date is handy), then you should be able to find and delete the offending entries.

Option Public
Dim TempNitem As NotesItem
Dim TempNm As NotesName
Dim session As  NotesSession
Dim db As NotesDatabase
Sub Initialize
	mailAddress = "YOUR_ADDRESS@HERE"
	Dim ws As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Dim partno As String
	Dim db As NotesDatabase
	Dim view As NotesView
	Dim doc As NotesDocument
	Dim collection As NotesDocumentCollection
	Dim memo As NotesDocument
	Dim body As NotesRichTextItem
	Dim range As NotesRichTextRange
	Dim count As Integer
	Set session = New NotesSession
	Set db = session.CurrentDatabase
	Set collection = db.UnprocessedDocuments
	Dim FldTitles(3) As String
	FldTitles(0) = "E-mail"
	FldTitles(1) = "Subject"
	FldTitles(2) = "Date sent"
	Set maildoc = db.CreateDocument
	maildoc.Form = "Memo"
	maildoc.Subject = "Summary"
	maildoc.SendTo = mailAddress
	Dim ritem As NotesRichTextItem
	Set ritem=New NotesRichTextItem(maildoc,"body") 
' passing the rich text item & other relevant details
	Set ritem = CreateTable(FldTitles, collection, ritem, "Sent items", "Summary created on " + Format(Now, "YYYY-MM-DD"))
End Sub
Function CreateTable(FldTitles As Variant, doccoll  As NotesDocumentCollection, rtitem As NotesRichTextItem,msgTitle As String,msgBody As String ) As NotesRichTextItem
	'Takes  Documentcollection & creates tabular information on to the passed   rtitem (rich text item)
	Set ritem=rtitem
	Set rtnav = ritem.CreateNavigator
	Set rstyle=session.CreateRichTextStyle 
	'heading in the body section of the mail
	Call  ritem.AppendStyle(rstyle)
	Call  ritem.AppendStyle(rstyle) 
	rows=doccoll.Count +1
	Call ritem.AppendTable(1, cols)
	Dim rtt As NotesRichTextTable
	Call rtnav.FindFirstElement(RTELEM_TYPE_TABLE)
	Set rtt = rtNav.GetElement 
	'heading of the table
	Call  ritem.AppendStyle(rstyle)
	For i=0 To UBound(FldTitles) - 1
		Call rtnav.FindNextElement(RTELEM_TYPE_TABLECELL)
		Call ritem.BeginInsert(rtnav) 
		Call ritem.AppendText(FldTitles(i))
		Call ritem.EndInsert
	Call  ritem.AppendStyle(rstyle)
	Dim count As Integer
	count = 0
	Set  doc=doccoll.GetFirstDocument
	While Not (doc Is Nothing)
		subject = doc.GetFirstItem("Subject").values(0)
		posted = doc.GetFirstItem("PostedDate").values(0)
		Set sendTo = doc.getFirstItem("SendTo")
		For i = 0 To UBound(sendTo.values)
			Call rtt.AddRow(1)
			Call rtnav.FindNextElement(RTELEM_TYPE_TABLECELL)   
			Call ritem.BeginInsert(rtnav)
			Call ritem.EndInsert
			Call rtnav.FindNextElement(RTELEM_TYPE_TABLECELL)   
			Call ritem.BeginInsert(rtnav)
			Call ritem.EndInsert
			Call rtnav.FindNextElement(RTELEM_TYPE_TABLECELL)   
			Call ritem.BeginInsert(rtnav)
			Call ritem.EndInsert
		count = count + 1
		Set doc=doccoll.GetNextDocument(doc)
	Set CreateTable=ritem
	MsgBox "E-mails summarized: " & count	
End Function

I find it helpful to save it as the "Summarize Recipients" agent and assign it to a toolbar button that runs @Command([RunAgent]; "Summarize Recipients").

Setting e-mail expectations: Roughly once a week

hamster-wheelI’ve seen the e-mail hamster-wheel that other people are stuck on, and I don’t want to go there. As for me, e-mail doesn’t make me feel important or needed or valued. E-mail is… well… it’s conversations that are hidden from the world, thoughts that I’m going to forget because no one else is going to come across them in a search engine and post comments. As lots of people have observed (including Luis Suarez, whom I knew at IBM): “E-mail is where knowledge goes to die.”

Still, e-mail is useful. I keep e-mail for following up with clients, coordinating with W- or with meetup organizers, introducing people, handling quick tech support for my mom, and answering the occasional private question that usually doesn’t have to be private anyway. I like getting quick questions, especially if I can send people links (although getting those questions as public comments works even better!). I like getting in-depth questions too, which I try to answer in blog posts whenever possible, add a note to my outline with the name of the person requesting it.

I reply to e-mail roughly once a week, although I check it more often to see if there’s anything that needs attention. Here’s how I work. Maybe you’ll pick up some ideas or tips! =)

I use my phone to quickly check e-mail while I’m walking or waiting. I get a lot of e-mail that I don’t particularly care about, even though I periodically unsubscribe from lists. The phone’s limited interface means that I generally don’t use it to reply to e-mail (unless I can say what I need in one or two sentences with no links), but I can delete unneeded messages and add stars to messages that need action.

Friday is my “catch up” day. I balance my company books, follow up on tasks I’m waiting for, and go through my e-mail, writing blog posts (like this one!) and e-mailing replies. The Share a Draft plugin for WordPress helps here because I can keep my ~1-post-a-day schedule while still giving people a sneak preview of any upcoming blog posts related to their question.

If there are important conversations I need to follow up on, I use Boomerang for Gmail. This archives the message for now, returning it to my inbox in case I haven’t received a reply within the specified timeframe. I also use Boomerang for Gmail’s “Send Later” feature to schedule e-mails so that I don’t have to set a reminder.

There are lots of other ways that people handle e-mail. There’s the idea of “Touch it once” – check mail only when you’re ready to handle it, and move important information to your to-do list. That would probably mean checking it more frequently, though, and I don’t want to commit time every day to do that. There’s being strict about checking only at specified times (such as once a day, or even once a week) and always having an Out of Office message turned on or putting that in your signature, but that felt odd too.  So here we are – I check mail frequently, respond occasionally, and try to move things into blog posts as much as possible.

There are trade-offs for my approach, of course. I could probably drum up more business and build more connections if I had a reputation for being instantly responsive… but I wouldn’t want to be shackled to my e-mail and I wouldn’t want my task list to be rearranged with every incoming message, so I’m fine with what I have.

Also, if it takes you a few weeks to reply too, no need to apologize. Almost all of my mail isn’t time-sensitive, and if it’s important to me, I’ll indicate the date I need a response by and I’ll follow up if time has passed.

E-mail doesn’t have to be a slave-driver. =)