13

I'm using javamail to send mails from my appengine application. It works perfectly in the deployment, but I can't figure out how to do this using the development server. Whenever I need to test the sendmail, I'm having to deploy the application which is quite annoying.

Background Information (Why logs don't work):

We know emails go to the logs on the appengine development server. However, the primary reason for wanting to send emails from the development server is to be able to test the format of the email. How does it look? Do changes need to be made to the email template so it looks good in email clients A, B, and C, and can it be done quickly without the hassle of deploying to a real, default appengine version each and every time.

We're not spammers. We're not trying to circumvent any type of security. In short, we want to legitimately be able to see the real, actual email in one or more email clients and then make code changes instantly so we can tweak them without having to go through the painstaking process of the edit, compile, wait 5 minutes for it to deploy, test, repeat cycle. Since there are no standards in how each email client renders an email, this painstaking process is amplified by trying to get something to work in many clients.

Question:

How can the Java Google App Engine Development server be configured to send emails from the local computer or an SMTP service for the purpose of testing emails sent to real, actual email clients?

jamesmortensen
  • 33,636
  • 11
  • 99
  • 120
akula1001
  • 4,576
  • 12
  • 43
  • 56

6 Answers6

12

From Eclipse, select the Run menu, Debug Configurations..., and then select your app’s configuration. Select the Arguments tab, then in the “VM arguments” section, set VM properties like this:

-Dmail.log_mail_level=WARNING -Dmail.log_mail_body=true

zawhtut
  • 8,335
  • 5
  • 52
  • 76
  • This doesn't actually send the email though, right? It just prints the raw markup to the logs? Correct? – jamesmortensen Jun 25 '12 at 18:46
  • It's been a long time I answered this question and I really don't remember. To test whether the mail is sending out or not, you can test it using test-mail-server-tool http://www.toolheap.com/test-mail-server-tool/ if you are working on Windows platform though. – zawhtut Jun 26 '12 at 03:25
6

When I worked with an e-mail service implementation I used a cool hint. So if you use MimeMessage too, and want just check if the message is formatted as expected, checking if attachments are there, HTML is well formatted, images are right referenced and so on, you could build the entire message, and during debug you could have some code like this:

MimeMessage msg = new MimeMessage(session);
...
if ("1".equals(System.getProperty("mail.debug"))) {
    msg.writeTo(new FileOutputStream(new File("/tmp/sentEmail.eml")));
}

Every time this is executed the MimeMessage instane will be saved to emailSent.eml. This file you can open with your e-mail reader and check if everything is fine.

Of course that you need to execute your application with -Dmail.debug=1 parameter.

An example with attached file, text message and html message with this approach could be like this:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.junit.Test;

public class MimeMessageTest {

    @Test
    public void tesstMimeMessage() throws MessagingException, FileNotFoundException, IOException {
        Session session = Session.getDefaultInstance(new Properties(), null);
        MimeMessage msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress("admin@foo.bar", "Foo Admin"));
        msg.addRecipient(Message.RecipientType.TO, new InternetAddress("baz@foo.bar", "Baz User"));
        msg.setSubject("Subject from admin e-mail to baz user");

        // create and fill the first message part
        MimeBodyPart mbp1 = new MimeBodyPart();
        mbp1.setText("test message and so on");
        mbp1.setContent("<h1>test message and so on in HTML</h1>", "text/html");

        // create the second message part
        MimeBodyPart mbp2 = new MimeBodyPart();

        // attach the file to the message
        FileDataSource fds = new FileDataSource("/tmp/fileToBeAttached");
        mbp2.setDataHandler(new DataHandler(fds));
        mbp2.setFileName(fds.getName());

        // create the Multipart and add its parts to it
        Multipart mp = new MimeMultipart();
        mp.addBodyPart(mbp1);
        mp.addBodyPart(mbp2);

        // add the Multipart to the message
        msg.setContent(mp);

        if ("1".equals(System.getProperty("debug"))) {
            msg.writeTo(new FileOutputStream(new File("/tmp/sentEmail.eml")));
        }
    }
}
Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
  • Hi Spaeth, this looks great! Nice idea. One question, can you write to the filesystem from the GAE Development server, or are you running this outside of the GAE Java SDK? – jamesmortensen Jun 30 '12 at 01:44
  • 1
    I'm running outside `GAE`. **BUT**, if you cannot save it to a file you could for instance: print it to standard out and copy/past to a file (as mimeMessage is a text file with all attachments Base64 encoded), this could be a solution to check if attachments are there, HTML formatted, links ok, images right referenced and so on. Therefore you need this change: `msg.writeTo(System.out);` instead of `msg.writeTo(new FileOutputStream(new File("/tmp/sentEmail.eml")));` – Francisco Spaeth Jun 30 '12 at 16:26
  • Ok, I am already writing the entire template to the output stream, but not as an email message but just as a template. This actually doesn't look like it will take me long to implement. I'll test this out weekend. Thank you. – jamesmortensen Jun 30 '12 at 18:55
  • another approach you could save the entire message on the store and create a servlet to access it. If you wanna just for test another possibility shall be store the last sent email in a static field and create a servlet just to download it with mime-type multipart/mixed – Francisco Spaeth Jul 01 '12 at 10:57
  • 1
    Spaeth, this is the best answer I've seen on the entire Internet for this particular problem! `writeTo(System.out)` then copy/paste to a file works! It's still a little slow to have to copy/paste, but this is a *great start* to solving a problem that has plagued many AppEngine developers since the platform was first introduced, and this is ***miles ahead*** of having to deploy everytime! +200 to you sir! – jamesmortensen Jul 02 '12 at 17:41
  • +1 for this answer.. msg.writeTo(new FileOutputStream(new File("/tmp/sentEmail.eml"))); will bring you to java.io.FileOutputStream is a restricted class.. – Daniel Robertus Apr 29 '13 at 07:18
3

From the docs:

When an application running in the development server calls the Mail service to send an email message, the message is printed to the log. The Java development server does not send the email message.

So just check the logs when you intend to send mail, and make sure that it shows up there. No real mail will actually get sent.

Jason Hall
  • 20,632
  • 4
  • 50
  • 57
  • 1
    This won't do because I need to check other things too; whether the message is formatted right, whether attachments are downloadable and whether the mail is getting delivered in the first place. – akula1001 Jun 21 '10 at 06:50
  • You can't do that kind of integration testing with the development server. I suggest you to either set up that in the deployment with for example a separate app or use your own mail server instead of App Engine APIs. – hleinone Jun 21 '10 at 08:37
  • @hleinone - Just wanted to let you know there is a bounty on this question, and it sounds like you might know how to solve this. – jamesmortensen Jun 28 '12 at 05:10
  • @jmort253 You may get better results by using a third-party mail provider like MailChimp http://mailchimp.com/ or MailGun http://mailgun.net/ -- these services are focused on email sending, and will probably give you more options than App Engine does. – Jason Hall Jun 28 '12 at 13:26
  • Hi Jason, thanks for your response. Since there is a bounty on this, I'm really looking for an actual example of such an implementation. So far, most answers on the Internet, including here, are mere speculation. Thanks again for the tips, and good luck! :) – jamesmortensen Jun 28 '12 at 14:20
2

GAE uses JavaMail, so it's not too difficult to get it working. There are two things you'll need to change.

The first is to set up your JavaMail session properly for your STMP server. To do this, instead of using Session.getDefaultInstance, use Session.getInstance, providing at least the mail.smtp.host properties. See JavaMail SMTP reference, or just look for a generic JavaMail SMTP tutortial.

The second change is that you need to stop GAE handling your emails. It does this because of the line

rfc822=gm

in META-INF/javamail.address.map in the SDK jar. You can either include your own address map - but that is annoying because I assume you only want it for debugging - or modify the address map from code. That is as simple as doing

session.setProtocolForAddress("rfc822", "smtp");

on the session you created in the first step. That should route all your emails to the standard SMTP handler.

Patrick Simpson
  • 554
  • 4
  • 12
1

You can do the following for setting up email on the development server

final String username = "xxxxxxxxx@gmail.com";//change accordingly
final String password = "xxxxxxx";//change accordingly

// Assuming you are sending email through gmail
String host = "smtp.gmail.com";

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", "587");

// Get the Session object.
Session session = Session.getInstance(props,
new javax.mail.Authenticator() {
 protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(username, password);
 }
});
session.setProtocolForAddress("rfc822", "smtp");

And use the session normally to send emails:

try {
    Message msg = new MimeMessage(session);
    msg.setFrom(new InternetAddress("xxxx@gmail.com", "xxxx"));
    msg.addRecipient(Message.RecipientType.TO,
    new InternetAddress("user@testdomain.com,"Mr. User"));
    msg.setSubject("Test email from GAE/J development");
    msg.setText("This is test:);
    Transport.send(msg);

} catch (Exception e) {
    e.printStackTrace();
}

Additionally you need to add the following two libraries in build path and under war/WEB-INF/lib:

  • javax.mail.jar
  • javax.activation.jar

You can find the links easily by googling them.

Finally if you want to use gmail as the smtp server, you need to go to your account, and enable access for less seucre apps https://www.google.com/settings/security/lesssecureapps

Dimitris F.
  • 477
  • 4
  • 4
0

In case anyone else stumbles across this question, here are the instructions for configuring your local GAE server to send mail

broofa
  • 37,461
  • 11
  • 73
  • 73