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() );
});
});
});
});
Posted with : Tech, General Programming, JavaScript