Command line mail merge
As shown before mail merging with Notes and {{mustache}} is simple and easy to code. To be able to run merging on the command line, I modified the bean and removed the XPages dependency and added a static main function. Now you can run it off the command line easily. It requires 5 parameters:
As usual YMMV
- the database name
- the CSV file
- a file with a HTML message including {{mustache}} tags
- a file with a Text message including {{mustache}} tags
- The senders eMail
package com.notessensei;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.MIMEEntity;
import lotus.domino.MIMEHeader;
import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;
import lotus.domino.Session;
import lotus.domino.Stream;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
public class MergeManager implements Serializable {
public static void main(String[] args) throws NotesException, IOException {
// We need 4 parameters: nsfToUse, addresses, html message, text message
// eMail field in addresses MUST be eMail
if (args.length < 5) {
System.out.println("Usage: java MergeManager maifile.nsf, addresses.csv, htmlmessage.txt, textmessage.txt sender");
System.exit(1);
}
String dbName = args[0];
String adrfilename = args[1];
String htmlfilename = args[2];
String txtfilename = args[3];
String sender = args[4];
MergeManager mergeManager = new MergeManager();
// Load the content into the objects
mergeManager.setRawAddresses(new Scanner(new File(adrfilename)).useDelimiter("\\Z").next());
mergeManager.setHtmlMessage(new Scanner(new File(htmlfilename)).useDelimiter("\\Z").next());
mergeManager.setTextMessage(new Scanner(new File(txtfilename)).useDelimiter("\\Z").next());
mergeManager.setFrom(sender);
// Spin up Notes
NotesThread.sinitThread();
Session s = NotesFactory.createSession();
Database userMail = s.getDatabase("", dbName);
// Set mailbox to null if you only want to generate the mails
// but not send them
Database mailbox = s.getDatabase("", "mail.box");
mergeManager.process(s, userMail, mailbox);
System.out.println(mergeManager.getStatus());
// Shut down
userMail.recycle();
mailbox.recycle();
NotesThread.stermThread();
}
private static final long serialVersionUID = 1L;
private String subject;
private String from;
private String rawAddresses;
private final Map<String, Map<String, String>> rcpData = new TreeMap<String, Map<String, String>>();
private String htmlMessage;
private String textMessage;
private String eMailField = "eMail";
private final ArrayList<String> fields = new ArrayList<String>();
private final MustacheFactory factory = new DefaultMustacheFactory();
private final StringBuilder statusMessages = new StringBuilder();
private void addOneDataLine(Map<String, Map<String, String>> allRCP, ArrayList<String> fields, String raw) {
Map<String, String> oneLine = new HashMap<String, String>();
String key = raw; // Backup pla
try {
String[] dataItems = raw.split(",");
for (int i = 0; i < dataItems.length; i++) {
oneLine.put(fields.get(i), dataItems[i]);
if (fields.get(i).equalsIgnoreCase(this.eMailField)) {
key = dataItems[i];
}
}
allRCP.put(key, oneLine);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getFields(ArrayList<String> list, String raw) {
String[] fieldNames = raw.split(",");
list.clear();
for (int i = 0; i < fieldNames.length; i++) {
list.add(fieldNames[i]);
}
return;
}
public String getStatus() {
return this.statusMessages.toString();
}
private void populateMail(Session s, Document mail, String htmlBody, String textBody, String receipient) throws NotesException {
s.setConvertMime(false);
final MIMEEntity emailRoot = mail.createMIMEEntity("Body");
// Primary Header
String fromSender = this.from;
MIMEHeader emailHeader = emailRoot.createHeader("Return-Path");
emailHeader.setHeaderVal(fromSender);
emailHeader = emailRoot.createHeader("From");
emailHeader.setHeaderVal(fromSender);
emailHeader = emailRoot.createHeader("Sender");
emailHeader.setHeaderVal(fromSender);
emailHeader = emailRoot.createHeader("Recipients");
emailHeader.setHeaderVal(receipient);
emailHeader = emailRoot.createHeader("To");
emailHeader.setHeaderVal(receipient);
emailHeader = emailRoot.createHeader("Subject");
emailHeader.setHeaderVal(this.subject);
// Text and HTML Body
MIMEEntity emailRootChild = emailRoot.createChildEntity();
final String boundary = System.currentTimeMillis() + "-" + String.valueOf(this.hashCode());
emailHeader = emailRootChild.createHeader("Content-Type");
emailHeader.setHeaderVal("multipart/alternative; boundary=\"" + boundary + "\"");
MIMEEntity emailChild = emailRootChild.createChildEntity();
Stream stream = s.createStream();
stream.writeText(textBody);
emailChild.setContentFromText(stream, "text/plain; charset=\"UTF-8\"", MIMEEntity.ENC_NONE);
stream.close();
emailChild = emailRootChild.createChildEntity();
stream = s.createStream();
stream.writeText(htmlBody);
emailChild.setContentFromText(stream, "text/html; charset=\"UTF-8\"", MIMEEntity.ENC_NONE);
stream.close();
stream.recycle();
stream = null;
s.setConvertMime(true);
}
public void process(Session s, Database database, Database mailbox) {
Mustache mHTML = this.factory.compile(new StringReader(this.htmlMessage), "eMailHTML");
Mustache mText = this.factory.compile(new StringReader(this.textMessage), "eMailPlain");
for (Map<String, String> oneRecord : this.rcpData.values()) {
this.sendOneMessage(s, database, mailbox, mHTML, mText, oneRecord);
}
}
private void processRawAdresses(String raw) {
ByteArrayInputStream in = new ByteArrayInputStream(raw.getBytes());
boolean firstLine = true;
Scanner scanner = new Scanner(in);
while (scanner.hasNextLine()) {
if (firstLine) {
this.rcpData.clear();
this.getFields(this.fields, scanner.nextLine());
firstLine = false;
} else {
this.addOneDataLine(this.rcpData, this.fields, scanner.nextLine());
}
}
this.statusMessages.append(String.format("%x Records loaded and ready\n", this.rcpData.size()));
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendOneMessage(Session s, Database database, Database mailbox, Mustache mHTML, Mustache mText,
Map<String, String> oneRecord) {
// Text as HTML and as plain Text
StringWriter htmlBody = new StringWriter();
StringWriter textBody = new StringWriter();
mHTML.execute(htmlBody, oneRecord);
mText.execute(textBody, oneRecord);
try {
Document mail = database.createDocument();
String rcpt = oneRecord.get(this.eMailField);
mail.replaceItemValue("Form", "Memo");
this.populateMail(s, mail, htmlBody.toString(), textBody.toString(), rcpt);
mail.save();
if (mailbox != null) {
mail.copyToDatabase(mailbox);
}
mail.recycle();
this.statusMessages.append("Mail send to ");
this.statusMessages.append(rcpt);
this.statusMessages.append("\n");
} catch (Exception <e) {
this.statusMessages.append(e.getMessage());
this.statusMessages.append("\n");
}
}
public void setEmailField(String mailField) {
this.eMailField = mailField;
}
public void setFrom(String from) {
this.from = from;
}
public void setHtmlMessage(String htmlMessage) {
this.htmlMessage = htmlMessage;
}
public void setRawAddresses(String rawAddresses) {
if (rawAddresses != null && !rawAddresses.equals(this.rawAddresses)) {
this.processRawAdresses(rawAddresses);
this.rawAddresses = rawAddresses;
}
}
public void setSubject(String subject) {
this.subject = subject;
}
public void setTextMessage(String textMessage) {
this.textMessage = textMessage;
}
}
As usual YMMV
Posted by Stephan H Wissel on 13 December 2014 | Comments (1) | categories: IBM Notes