Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added JavaMail API examples for App Engine #208

Merged
merged 2 commits into from
Apr 28, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions appengine/mail/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# JavaMail API Email Sample for Google App Engine Standard Environment

This sample demonstrates how to use [JavaMail][javamail-api] on [Google App Engine
standard environment][ae-docs].

See the [sample application documentaion][sample-docs] for more detailed
instructions.

[ae-docs]: https://cloud.google.com/appengine/docs/java/
[javamail-api]: http://javamail.java.net/
[sample-docs]: https://cloud.google.com/appengine/docs/java/mail/

## Setup
1. Update the `<application>` tag in `src/main/webapp/WEB-INF/appengine-web.xml`
with your project name.
1. Update the `<version>` tag in `src/main/webapp/WEB-INF/appengine-web.xml`
with your version name.

## Running locally
$ mvn appengine:devserver

## Deploying
$ mvn appengine:update
66 changes: 66 additions & 0 deletions appengine/mail/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!--
Copyright 2016 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project>
<modelVersion>4.0.0</modelVersion>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to reference the parent pom here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<groupId>com.example.appengine</groupId>
<artifactId>appengine-mail</artifactId>
<parent>
<groupId>com.google.cloud</groupId>
<artifactId>doc-samples</artifactId>
<version>1.0.0</version>
<relativePath>../..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>
<build>
<!-- for hot reload of the web application -->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>3.3</version>
<artifactId>maven-compiler-plugin</artifactId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if you use the parent pom, the compiler plugin isn't required here. Actually, all that's required would have been to define <maven.compiler.source> and <maven.compiler.target>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this looks like, is there an example in another pom.xml file in this project? I couldn't seem to find one.

<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- Parent POM defines ${appengine.sdk.version} (updates frequently). -->
<plugin>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>${appengine.sdk.version}</version>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// [START handle_discussion_email]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs license and should be a .java file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Moved to MailHandlerBase.java and HandleDiscussionEmail.java

public class HandleDiscussionEmail extends MailHandlerBase {

public HandleDiscussionEmail() { super("discuss-(.*)@(.*)"); }

@Override
protected boolean processMessage(HttpServletRequest req, HttpServletResponse res)
throws ServletException
{
MimeMessage msg = getMessageFromRequest(req);
Matcher match = getMatcherFromRequest(req);
...
}

}
// [END handle_discussion_email]

// [START email_filter]
<filter>
<filter-name>HandleDiscussionEmail</filter-name>
<filter-class>pkg.HandleDiscussionEmail</filter-class>
</filter>
<filter-mapping>
<filter-name>HandleDiscussionEmail</filter-name>
<url-pattern>/_ah/mail/*</url-pattern>
</filter-mapping>
// [END email_filter]

// [START abstract_mail_handler]
public abstract class MailHandlerBase implements Filter {

private Pattern pattern = null;

protected MailHandlerBase(String pattern) {
if (pattern == null || pattern.trim().length() == 0)
{
throw new IllegalArgumentException("Expected non-empty regular expression");
}
this.pattern = Pattern.compile("/_ah/mail/"+pattern);
}

@Override public void init(FilterConfig config) throws ServletException { }

@Override public void destroy() { }

/**
* Process the message. A message will only be passed to this method
* if the servletPath of the message (typically the recipient for
* appengine) satisfies the pattern passed to the constructor. If
* the implementation returns false, control is passed
* to the next filter in the chain. If the implementation returns
* true, the filter chain is terminated.
*
* The Matcher for the pattern can be retrieved via
* getMatcherFromRequest (e.g. if groups are used in the pattern).
*/
protected abstract boolean processMessage(HttpServletRequest req, HttpServletResponse res) throws ServletException;

@Override
public void doFilter(ServletRequest sreq, ServletResponse sres, FilterChain chain)
throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse res = (HttpServletResponse) sres;

MimeMessage message = getMessageFromRequest(req);
Matcher m = applyPattern(req);

if (m != null && processMessage(req, res)) {
return;
}

chain.doFilter(req, res); // Try the next one

}

private Matcher applyPattern(HttpServletRequest req) {
Matcher m = pattern.matcher(req.getServletPath());
if (!m.matches()) m = null;

req.setAttribute("matcher", m);
return m;
}

protected Matcher getMatcherFromRequest(ServletRequest req) {
return (Matcher) req.getAttribute("matcher");
}

protected MimeMessage getMessageFromRequest(ServletRequest req) throws ServletException {
MimeMessage message = (MimeMessage) req.getAttribute("mimeMessage");
if (message == null) {
try {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
message = new MimeMessage(session, req.getInputStream());
req.setAttribute("mimeMessage", message);

} catch (MessagingException e) {
throw new ServletException("Error processing inbound message", e);
} catch (IOException e) {
throw new ServletException("Error processing inbound message", e);
}
}
return message;
}
}
// [END abstract_mail_handler]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.appengine.mail;

// [START mail_handler_servlet]
import java.io.IOException;
import java.util.Properties;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MailHandlerServlet extends HttpServlet {

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
try {
MimeMessage message = new MimeMessage(session, req.getInputStream());
} catch (MessagingException e) {
// ...
}
// ...
}
}
// [END mail_handler_servlet]
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.appengine.mail;

// [START simple_includes]
import java.io.IOException;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
// [END simple_includes]

// [START multipart_includes]
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import javax.activation.DataHandler;
import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
// [END multipart_includes]

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class MailServlet extends HttpServlet {

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String type = req.getParameter("type");
if (type != null && type.equals("multipart")) {
resp.getWriter().print("Sending HTML email with attachment.");
sendMultipartMail();
} else {
resp.getWriter().print("Sending simple email.");
sendSimpleMail();
}
}

private void sendSimpleMail() {
// [START simple_example]
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);

try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("admin@example.com", "Example.com Admin"));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress("user@example.com", "Mr. User"));
msg.setSubject("Your Example.com account has been activated");
Transport.send(msg);
} catch (AddressException e) {
// ...
} catch (MessagingException e) {
// ...
} catch (UnsupportedEncodingException e) {
// ...
}
// [END simple_example]
}

private void sendMultipartMail() {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);

String msgBody = "...";

try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("admin@example.com", "Example.com Admin"));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress("user@example.com", "Mr. User"));
msg.setSubject("Your Example.com account has been activated");
msg.setText(msgBody);

// [START multipart_example]
String htmlBody = ""; // ...
byte[] attachmentData = null; // ...
Multipart mp = new MimeMultipart();

MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(htmlBody, "text/html");
mp.addBodyPart(htmlPart);

MimeBodyPart attachment = new MimeBodyPart();
InputStream attachmentDataStream = new ByteArrayInputStream(attachmentData);
attachment.setFileName("manual.pdf");
attachment.setContent(attachmentDataStream, "application/pdf");
mp.addBodyPart(attachment);

msg.setContent(mp);
// [END multipart_example]

Transport.send(msg);

} catch (AddressException e) {
// ...
} catch (MessagingException e) {
// ...
} catch (UnsupportedEncodingException e) {
// ...
}
}
}
26 changes: 26 additions & 0 deletions appengine/mail/src/main/webapp/WEB-INF/appengine-web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- [START_EXCLUDE] -->
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- [END_EXCLUDE] -->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>YOUR-PROJECT-ID</application>
<version>YOUR-VERSION-ID</version>
<threadsafe>true</threadsafe>

<!-- [START handle_incoming_mail] -->
<inbound-services>
<service>mail</service>
</inbound-services>
<!-- [END handle_incoming_mail] -->
</appengine-web-app>
Loading