A blog about software development, primarily in Java and about web applications.

Showing posts with label email. Show all posts
Showing posts with label email. Show all posts

Wednesday, June 17, 2009

Resending Email (.eml) filesh

I recently had to resend a bunch of old email files and I wanted to preserve the original sent date on them.

I couldn't find an add-on for Thunderbird to do this. I did see an add-on that allows you set a future date for an email, but not a past date. I also couldn't find any other simple program or Cygwin command to use. So I just did it with Java and it ended up being rather simple.

The key thing here was preserving the sent date. I tried setting the clock on my machine back in time, but that doesn't really work because I'd have to reset it to a different date and time for each email and that's just too much manual work. My internet connection also doesn't like it when my machine's time is way off from reality.

So my solution was to first, in Thunderbird (my email client), save all of the emails I wanted to resend as .eml files in a folder. Then I wrote this simple program using Java Mail's API to read in the .eml file and to send the email again preserving all of the fields, except the TO address, which I changed based on my needs.

Here's the program:

import java.io.*;
import java.util.*;

import javax.mail.*;
import javax.mail.internet.*;

public class Eml {

public static void main(String args[]) throws Exception {

String host = "smtp.foo.edu";
String from = "phu@foo.edu";
String to = "bar1@foo.edu, bar2@foo.edu";

Properties props = System.getProperties();
props.setProperty("mail.smtp.host", host);
props.put("mail.transport.protocol", "smtp");

Session mailSession = Session.getDefaultInstance(props, null);
mailSession.setDebug(true);

File emlFile = new File(args[0]);
InputStream source = new FileInputStream(emlFile);

MimeMessage message = new MimeMessage(mailSession, source);

System.out.println("--------------");
System.out.println("To: " + Arrays.asList(message.getAllRecipients()));
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Subject: " + message.getSubject());
System.out.println("Sent Date: " + message.getSentDate());
System.out.println("Body: " + message.getContent());

message.setRecipients(Message.RecipientType.TO, to);
Transport.send(message);

System.out.println("Message sent....");
System.out.println("--------------");
}
}

It takes one argument, the name of the file. I used a simple Cygwin for command to loop through the *.eml files and run this program for each one. I could have added that logic to this Java program, but it was just as quick and easy to do it this way.

There's no error handling here and I used wildcards in the import lines which I usually avoid doing, but this works. I ran with it Java 5.

Tuesday, April 29, 2008

Mailman Mailing Lists and Spam Prevention

We recently had an issue with spam coming to a mailing list that only our application should be sending to. We use Mailman to manage our mailing list and have our own mail server. The mailing list is set up to only allow emails from two email addresses: one an administrative address we use for manual announcements we need to make, the other the name of the email list itself which we use for the automated emails.

The spammers started sending requests into our mail server with one of our allowed email addresses. I looked in the Mailman interface to see if there was some option that would block these spam attempts and didn't see anything that would apply. We were already restricting who could send to the lists and had all other addresses either blocked or moderated. Two obvious solutions were for IT to configure our spam filtering software to block these spam attempts or configure the mail server to not allow emails with our FROM address that originate outside the firewall. For various reasons, our IT group said they could not do either.

The solution we found was to add an "Approved: [password]" header as the first line in the body of the email (followed by one blank line). Mailman will treat this line as an email header and make sure the password matches the administrative password set in the Mailman UI (this is different than the moderator's email address).

Here's the article article we found at python.org describing the solution. The only piece missing was which password to set in the UI.

The password we use is essentially a shared secret, which isn't the most secure thing, so we've externalized it's value into a property file. This allows our Operations team to change the password if it gets compromised without involving development.

One last note, if you previously configured Mailman to allow (unmoderated) emails from your FROM address, you will want to to remove that (in Mailman's Privacy Options -> Sender Filters) or all emails will still be allowed, even if you have no password or an incorrect password.