Using JavaMail JARs for OAuth SMTP without losing access to Google App Engine Mail

2 views
Skip to first unread message

ArjunKumar via StackOverflow

unread,
Dec 11, 2014, 11:37:45 AM12/11/14
to google-appengin...@googlegroups.com

Google App Engine's Email service uses JavaMail JARs included in the AppEngine SDK. It specifically asks us not to use Oracle's JARs.

But in order to use Google OAuth 2.0 for sending emails using SMTP, we need Oracle's JavaMail JARs.

Any idea on how to achieve this? I'm stuck. Our software's internal features use AppEngine mails to send emails within our team, and our clients need Google OAuth SMTP to send mails on behalf of their email address.

After including Oracle's JARs, I get this exception while trying to use normal AppEngine Mail:

javax.mail.SendFailedException: Send failure (com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 25; timeout -1 (java.net.SocketException: Permission denied: Attempt to access a blocked recipient without permission.))
at javax.mail.Transport.send(Transport.java:163)
at javax.mail.Transport.send(Transport.java:48)
at app.util.EmailUtil.sendMail_AppEngine(EmailUtil.java:948)

I hope someone helps me out here.



Please DO NOT REPLY directly to this email but go to StackOverflow:
http://stackoverflow.com/questions/27427781/using-javamail-jars-for-oauth-smtp-without-losing-access-to-google-app-engine-ma

ArjunKumar via StackOverflow

unread,
Dec 11, 2014, 11:47:47 AM12/11/14
to google-appengin...@googlegroups.com

Google App Engine's Email service uses JavaMail JARs included in the AppEngine SDK. It specifically asks us not to use Oracle's JARs.

But in order to use Google OAuth 2.0 for sending emails using SMTP, we need Oracle's JavaMail JARs.

Any idea on how to achieve this? I'm stuck. Our software's internal features use AppEngine mails to send emails within our team, and our clients need Google OAuth SMTP to send mails on behalf of their email address.

After including Oracle's JARs, I get this exception while trying to use normal AppEngine Mail:

javax.mail.SendFailedException: Send failure (com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 25; timeout -1 (java.net.SocketException: Permission denied: Attempt to access a blocked recipient without permission.))
at javax.mail.Transport.send(Transport.java:163)
at javax.mail.Transport.send(Transport.java:48)
at app.util.EmailUtil.sendMail_AppEngine(EmailUtil.java:948)

Update: Here is the code I use to send mails using OAuth

        Properties props = new Properties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.starttls.required", "true");
        props.put("mail.smtp.sasl.enable", "false");
        Session session = Session.getInstance(props);
        session.setDebug(false);

        final URLName unusedUrlName = null;
        SMTPTransport transport = new SMTPTransport(session, unusedUrlName);
        transport.connect("smtp.gmail.com", 587, fromAddress, null);

 byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", lFrom, oauthToken).getBytes();
        response = BASE64EncoderStream.encode(response);

        transport.issueCommand("AUTH XOAUTH2 " + new String(response),
                235);

        MimeMessage msg = new MimeMessage( session );

        msg.setFrom( new InternetAddress( fromAddress , fromName ) );
        msg.setRecipients( Message.RecipientType.TO , InternetAddress.parse( toAddress , false ) );

        msg.setSubject( emailSubject );
        MimeBodyPart htmlPart = new MimeBodyPart();
        Multipart multiPart = new MimeMultipart();

        htmlPart.setContent( "<html>email content</html>" , "text/html; charset=UTF-8" );
        multiPart.addBodyPart( htmlPart );
        msg.setContent( multiPart );
        msg.saveChanges();

        transport.sendMessage(msg, msg.getAllRecipients());

koma via StackOverflow

unread,
Dec 11, 2014, 11:57:48 AM12/11/14
to google-appengin...@googlegroups.com

This code works for me :

import java.security.Provider;
import java.security.Security;
import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Session;
import javax.mail.URLName;

import com.sun.mail.gimap.GmailSSLStore;
import com.sun.mail.smtp.SMTPTransport;

/**
 * Performs OAuth2 authentication.
 * 
 * <p>
 * Before using this class, you must call {@code initialize} to install the
 * OAuth2 SASL provider.
 */
public class XOAuth2Authenticator {

    private static final Logger logger = Logger.getLogger(XOAuth2Authenticator.class.getName());

    public static final class OAuth2Provider extends Provider {
        private static final long serialVersionUID = 1L;

        public OAuth2Provider() {
            super("Google OAuth2 Provider", 1.0, "Provides the XOAUTH2 SASL Mechanism");
            put("SaslClientFactory.XOAUTH2", "be.vsko.davidgadget.server.gmail.OAuth2SaslClientFactory");
        }
    }

    /**
     * Installs the OAuth2 SASL provider. This must be called exactly once
     * before calling other methods on this class.
     */
    public static void initialize() {
        Security.addProvider(new OAuth2Provider());
    }

    /**
     * Connects and authenticates to an IMAP server with OAuth2. You must have
     * called {@code initialize}.
     * 
     * @param host
     *            Hostname of the imap server, for example
     *            {@code imap.googlemail.com}.
     * @param port
     *            Port of the imap server, for example 993.
     * @param userEmail
     *            Email address of the user to authenticate, for example
     *            {@code oa...@gmail.com}.
     * @param oauthToken
     *            The user's OAuth token.
     * @param debug
     *            Whether to enable debug logging on the IMAP connection.
     * 
     * @return An authenticated GmailSSLStore that can be used for IMAP operations.
     */
    public static GmailSSLStore connectToImap(String host, int port, String userEmail, String oauthToken, boolean debug)
            throws Exception {

        logger.info("connecting to IMAP for user " + userEmail);

        Properties props = new Properties();
        // props.put("mail.imaps.sasl.enable", "true");
        // props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
        props.put("mail.gimaps.sasl.enable", "true");
        props.put("mail.gimaps.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        props.put("mail.store.protocol", "gimaps");
        Session session = Session.getInstance(props);
        props = session.getProperties();
        // props.put("mail.imaps.sasl.enable", "true");
        // props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
        props.put("mail.gimaps.sasl.enable", "true");
        props.put("mail.gimaps.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        props.put("mail.store.protocol", "gimaps");
        session.setDebug(debug);

        final URLName unusedUrlName = null;
        final String emptyPassword = "";

        GmailSSLStore gmailStore = new GmailSSLStore(session, unusedUrlName);
        gmailStore.connect(host, port, userEmail, emptyPassword);

        logger.info("SUCCESS connecting to IMAP for user " + userEmail);

        return gmailStore;

        // IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
        // store.connect(host, port, userEmail, emptyPassword);
        // return store;
    }

    /**
     * Connects and authenticates to an SMTP server with OAuth2. You must have
     * called {@code initialize}.
     * 
     * @param host
     *            Hostname of the smtp server, for example
     *            {@code smtp.googlemail.com}.
     * @param port
     *            Port of the smtp server, for example 587.
     * @param userEmail
     *            Email address of the user to authenticate, for example
     *            {@code oa...@gmail.com}.
     * @param oauthToken
     *            The user's OAuth token.
     * @param debug
     *            Whether to enable debug logging on the connection.
     * 
     * @return An authenticated SMTPTransport that can be used for SMTP
     *         operations.
     */
    public static SMTPTransport connectToSmtp(Session session, String host, int port, String userEmail) throws Exception {

        logger.info("connecting to SMTP for user " + userEmail);

        final URLName unusedUrlName = null;
        SMTPTransport transport = new SMTPTransport(session, unusedUrlName);
        // If the password is non-null, SMTP tries to do AUTH LOGIN.
        final String emptyPassword = "";
        transport.connect(host, port, userEmail, emptyPassword);

        logger.info("SUCCESS connecting to SMTP for user " + userEmail);

        return transport;
    }

    public static Session getSmtpSession(String oauthToken, boolean debug) {
        Properties props = new Properties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.starttls.required", "true");
        props.put("mail.smtp.sasl.enable", "true");
        props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        Session session = Session.getInstance(props);
        props = session.getProperties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.starttls.required", "true");
        props.put("mail.smtp.sasl.enable", "true");
        props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        session.setDebug(debug);
        return session;
    }
}

With this in place, you can :

XOAuth2Authenticator.initialize();
Session smtpSession = XOAuth2Authenticator.getSmtpSession(oauthToken, true);
SMTPTransport transport = XOAuth2Authenticator.connectToSmtp(smtpSession, "smtp.gmail.com", 587, email);

and now use transport as usual.

PS: The easier way round IMO, is to use the new GMAIL api.



Please DO NOT REPLY directly to this email but go to StackOverflow:
http://stackoverflow.com/questions/27427781/using-javamail-jars-for-oauth-smtp-without-losing-access-to-google-app-engine-ma/27428310#27428310
Reply all
Reply to author
Forward
0 new messages