Mini E-mail Campaign With Node.js
January 12, 2015
Over the weekend I had what at first appeared to be a small challenge: send out a few hundreds e-mails for a non-profit's outreach campaign. MailChimp and other mailings lists were not a good fit, as these messages were of the cold-call variety, and a formal mailing list felt too spammy. Initially I wrote a utility in .NET, but ended up solving with Node.js instead due to timeouts experienced with SmtpClient.
Requirements: parse a CSV file and then send HTML-formatted e-mail through an SMTP server. The body of the e-mail has a place holder for the recipient's name. Log the results.
Really, this should be trivial. It does not take a team lead software engineer to write this. But somehow my .NET client just kept timing out. I tried several servers and had the same response. I disabled firewalls, but with no luck. Finally, I decided to just try another language. As I've not written anything in Perl or PHP in many years (both well suited to the task), I chose Node.js. And I was able to send e-mail on the first try.
It seems there is something wrong with the System.Net.Mail.SmtpClient. I tried both synchronous and asynchronous, by the way. And I've used the SmtpClient with 2.0 and 3.5 applications, though never with 4.0+. There are a few people who have experienced similar problems. Although disabling the firewalls did not help, I still wonder there is something about the Windows 8 security settings.
What I realized is that I was just wasting my time trying to get this working .NET. Switching to Node.js also gave me a good opportunity to get some practice in with this elegant, highly-componetized framework. The keys to success were using the built-in filesystem API and NPM installing the csv and emailjs modules.
Though quick-and-dirty, I give this to the Internet for my own future reference if nothing else.
var campaign = { user: "arthur@the.roundtable.uk", password: "12345678909876", host: "mailserver.the.roundtable.com", port: 465, templateFile: "c:/temp/invitationToGrailSearch.txt", logFile: "c:/temp/invitationToGrailSearch.log", addressFile: "c:/temp/completeListOfTheKnightsOfAlbion.txt", from: "King Arthur <arthur@the.roundtable.uk>", subject: "Open Invitation to Join in the Grail Hunt" }; var csv = require('csv'); var fs = require('fs'); var logToFile = function (message) { fs.appendFileSync(campaign.logFile, message + "\r\n"); }; // Setup mail server connection var email = require("emailjs/email"); var server = email.server.connect( { user: campaign.user, password: campaign.password, host: campaign.host, port: campaign.port, ssl: true }); // Read in the template file var template = fs.readFileSync(campaign.templateFile).toString(); // Now read in the address file, containing lines with "Name, email" fs.readFile(campaign.addressFile, function (err, data) { if (err) { logToFile(err); throw err; } // now that we've read the file, need to parse it csv.parse(data.toString(), function (parseError, output) { if (parseError) { logToFile(parseError); throw parseError; } // for each line from the file var lineNumber = 0; output.forEach(function (record) { lineNumber++; if (record.length != 2) { logToFile("Invalid entry on line " + lineNumber.toString() + ", which has " + record.length.toString() + " columns"); return; } var name = record[0].trim(); var email = record[1].trim(); var message = { from: campaign.from, to: '"' + name + '" <' + email + '>', subject: campaign.subject, attachment: [ // my template only has a single placeholder - "[person]" { data: template.replace('[person]', name), alternative: true } ] }; server.send(message, function (err, message) { logToFile(message.header.to.toString() + ", " + (err || 'success').toString() ); }); }); }); });
No TrackBacks
TrackBack URL: http://www.safnet.com/fcgi-bin/mt/mt-tb.cgi/146
Leave a comment