Skip to content

Commit e60027b

Browse files
committed
#421: Added support for OAUTH2 using Google's XOAUTH2 reference implementation. Code double check and junit tests still pending...
1 parent 9cd0807 commit e60027b

File tree

16 files changed

+306
-58
lines changed

16 files changed

+306
-58
lines changed

modules/batch-module/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<dependency>
3535
<groupId>org.simplejavamail</groupId>
3636
<artifactId>smtp-connection-pool</artifactId>
37-
<version>2.0.2</version>
37+
<version>2.1.0</version>
3838
</dependency>
3939
</dependencies>
4040
</project>

modules/core-module/src/main/java/org/simplejavamail/api/mailer/MailerRegularBuilder.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public interface MailerRegularBuilder<T extends MailerRegularBuilder<?>> extends
3636
* {@link TransportStrategy#SMTP_TLS}. Defaults to {@link TransportStrategy#SMTP}.
3737
*/
3838
T withTransportStrategy(@NotNull TransportStrategy transportStrategy);
39-
39+
4040
/**
4141
* Delegates to {@link #withSMTPServerHost(String)}, {@link #withSMTPServerPort(Integer)}, {@link #withSMTPServerUsername(String)} and {@link
4242
* #withSMTPServerPassword(String)}.
@@ -47,6 +47,17 @@ public interface MailerRegularBuilder<T extends MailerRegularBuilder<?>> extends
4747
* @param password Optional password that defaults to pre-configured property if left empty.
4848
*/
4949
T withSMTPServer(@Nullable String host, @Nullable Integer port, @Nullable String username, @Nullable String password);
50+
51+
/**
52+
* Delegates to {@link #withSMTPServerHost(String)}, {@link #withSMTPServerPort(Integer)}, {@link #withSMTPServerUsername(String)} and {@link
53+
* #withSMTPOAuth2Token(String)}.
54+
*
55+
* @param host Optional host that defaults to pre-configured property if left empty.
56+
* @param port Optional port number that defaults to pre-configured property if left empty.
57+
* @param username Optional username that defaults to pre-configured property if left empty.
58+
* @param oauth2Token Optional oauth2Token that defaults to pre-configured property if left empty.
59+
*/
60+
T withSMTPServerOAuth2(@Nullable String host, @Nullable Integer port, @Nullable String username, @Nullable String oauth2Token);
5061

5162
/**
5263
* Delegates to {@link #withSMTPServerHost(String)}, {@link #withSMTPServerPort(Integer)} and {@link #withSMTPServerUsername(String)}.
@@ -100,6 +111,14 @@ public interface MailerRegularBuilder<T extends MailerRegularBuilder<?>> extends
100111
@Cli.ExcludeApi(reason = "API is a subset of another API method")
101112
T withSMTPServerPassword(@Nullable String password);
102113

114+
/**
115+
* Sets the optional OAuth2 token. Will default to pre-configured property if left empty.
116+
*
117+
* @param oauth2Token Optional oauth2 token that defaults to pre-configured property if left empty.
118+
*/
119+
@Cli.ExcludeApi(reason = "API is a subset of another API method")
120+
T withSMTPOAuth2Token(@Nullable String oauth2Token);
121+
103122
/**
104123
* Configures the session with the right property to use your own factory for obtaining SSL connections.
105124
* <p>

modules/core-module/src/main/java/org/simplejavamail/api/mailer/config/ServerConfig.java

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public interface ServerConfig {
1010
@NotNull Integer getPort();
1111
@Nullable String getUsername();
1212
@Nullable String getPassword();
13+
@Nullable String getOAuth2Token();
1314
@Nullable String getCustomSSLFactoryClass();
1415
@Nullable SSLSocketFactory getCustomSSLFactoryInstance();
1516
}

modules/core-module/src/main/java/org/simplejavamail/api/mailer/config/TransportStrategy.java

+139-7
Original file line numberDiff line numberDiff line change
@@ -411,31 +411,31 @@ public String propertyNameUsername() {
411411
public String propertyNameAuthenticate() {
412412
return "mail.smtp.auth";
413413
}
414-
414+
415415
/**
416416
* @return "mail.smtp.socks.host"
417417
*/
418418
@Override
419419
public String propertyNameSocksHost() {
420420
return "mail.smtp.socks.host";
421421
}
422-
422+
423423
/**
424424
* @return "mail.smtp.socks.port"
425425
*/
426426
@Override
427427
public String propertyNameSocksPort() {
428428
return "mail.smtp.socks.port";
429429
}
430-
430+
431431
/**
432432
* @return "mail.smtp.connectiontimeout"
433433
*/
434434
@Override
435435
public String propertyNameConnectionTimeout() {
436436
return "mail.smtp.connectiontimeout";
437437
}
438-
438+
439439
/**
440440
* @return "mail.smtp.timeout"
441441
*/
@@ -451,15 +451,15 @@ public String propertyNameTimeout() {
451451
public String propertyNameWriteTimeout() {
452452
return "mail.smtp.writetimeout";
453453
}
454-
454+
455455
/**
456456
* @return "mail.smtp.from"
457457
*/
458458
@Override
459459
public String propertyNameEnvelopeFrom() {
460460
return "mail.smtp.from";
461461
}
462-
462+
463463
/**
464464
* @return "mail.smtp.ssl.trust"
465465
*/
@@ -477,6 +477,135 @@ public int getDefaultServerPort() {
477477
return DEFAULT_SMTP_TLS_PORT;
478478
}
479479

480+
/**
481+
* @return "mail.smtp.ssl.checkserveridentity"
482+
*/
483+
@Override
484+
public String propertyNameCheckServerIdentity() {
485+
return "mail.smtp.ssl.checkserveridentity";
486+
}
487+
},
488+
489+
SMTP_OAUTH2 {
490+
491+
/**
492+
* When no server port has been configured either through property or by builder api (Java / CLI),
493+
* port <code>{@value}</code> will be used.
494+
*/
495+
private static final int DEFAULT_SMTP_OAUTH_PORT = 587;
496+
497+
/**
498+
* @see TransportStrategy#SMTP_OAUTH2
499+
*/
500+
@Override
501+
public Properties generateProperties() {
502+
final Properties props = super.generateProperties();
503+
props.put("mail.transport.protocol", "smtp");
504+
props.put("mail.smtp.starttls.enable", "true");
505+
props.put("mail.smtp.starttls.required", "true");
506+
507+
props.put("mail.smtp.sasl.enable", "true");
508+
props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
509+
return props;
510+
}
511+
512+
/**
513+
* @return "mail.smtp.host"
514+
*/
515+
@Override
516+
public String propertyNameHost() {
517+
return "mail.smtp.host";
518+
}
519+
520+
/**
521+
* @return "mail.smtp.port"
522+
*/
523+
@Override
524+
public String propertyNamePort() {
525+
return "mail.smtp.port";
526+
}
527+
528+
/**
529+
* @return "mail.smtp.user"
530+
*/
531+
@Override
532+
public String propertyNameUsername() {
533+
return "mail.smtp.user";
534+
}
535+
536+
/**
537+
* @return "mail.smtp.auth"
538+
*/
539+
@Override
540+
public String propertyNameAuthenticate() {
541+
return "mail.smtp.auth";
542+
}
543+
544+
/**
545+
* @return "mail.smtp.socks.host"
546+
*/
547+
@Override
548+
public String propertyNameSocksHost() {
549+
return "mail.smtp.socks.host";
550+
}
551+
552+
/**
553+
* @return "mail.smtp.socks.port"
554+
*/
555+
@Override
556+
public String propertyNameSocksPort() {
557+
return "mail.smtp.socks.port";
558+
}
559+
560+
/**
561+
* @return "mail.smtp.connectiontimeout"
562+
*/
563+
@Override
564+
public String propertyNameConnectionTimeout() {
565+
return "mail.smtp.connectiontimeout";
566+
}
567+
568+
/**
569+
* @return "mail.smtp.timeout"
570+
*/
571+
@Override
572+
public String propertyNameTimeout() {
573+
return "mail.smtp.timeout";
574+
}
575+
576+
/**
577+
* @return "mail.smtp.writetimeout"
578+
*/
579+
@Override
580+
public String propertyNameWriteTimeout() {
581+
return "mail.smtp.writetimeout";
582+
}
583+
584+
/**
585+
* @return "mail.smtp.from"
586+
*/
587+
@Override
588+
public String propertyNameEnvelopeFrom() {
589+
return "mail.smtp.from";
590+
}
591+
592+
/**
593+
* @return "mail.smtp.ssl.trust"
594+
*/
595+
@Override
596+
public String propertyNameSSLTrust() {
597+
return "mail.smtp.ssl.trust";
598+
}
599+
600+
/**
601+
* @return {@value DEFAULT_SMTP_OAUTH_PORT}
602+
* @see #DEFAULT_SMTP_OAUTH_PORT
603+
*/
604+
@Override
605+
public int getDefaultServerPort() {
606+
return DEFAULT_SMTP_OAUTH_PORT;
607+
}
608+
480609
/**
481610
* @return "mail.smtp.ssl.checkserveridentity"
482611
*/
@@ -496,6 +625,8 @@ public String propertyNameCheckServerIdentity() {
496625
* as a custom session when sending emails.
497626
*/
498627
private static final String TRANSPORT_STRATEGY_MARKER = "simplejavamail.transportstrategy";
628+
629+
public static final String OAUTH2_TOKEN_PROPERTY = "mail.imaps.sasl.mechanisms.oauth2.oauthToken";
499630

500631
/**
501632
* For internal use only.
@@ -601,11 +732,12 @@ public static TransportStrategy findStrategyForSession(final Session session) {
601732
}
602733

603734
public String toString(final Properties properties) {
604-
return format("session (host: %s, port: %s, username: %s, authenticate: %s, transport: %s)",
735+
return format("session (host: %s, port: %s, username: %s, authenticate: %s, oauth2: %s, transport: %s)",
605736
properties.get(propertyNameHost()),
606737
properties.get(propertyNamePort()),
607738
properties.get(propertyNameUsername()),
608739
properties.get(propertyNameAuthenticate()),
740+
properties.containsKey(TransportStrategy.OAUTH2_TOKEN_PROPERTY),
609741
this);
610742
}
611743
}

modules/core-module/src/main/java/org/simplejavamail/config/ConfigLoader.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@
99
import org.slf4j.Logger;
1010
import org.slf4j.LoggerFactory;
1111

12-
import java.io.File;
13-
import java.io.FileInputStream;
14-
import java.io.FileNotFoundException;
15-
import java.io.IOException;
16-
import java.io.InputStream;
12+
import java.io.*;
1713
import java.util.HashMap;
1814
import java.util.Map;
1915
import java.util.Properties;
@@ -39,6 +35,7 @@
3935
* <li>simplejavamail.smtp.port</li>
4036
* <li>simplejavamail.smtp.username</li>
4137
* <li>simplejavamail.smtp.password</li>
38+
* <li>simplejavamail.smtp.oauth2token</li>
4239
* <li>simplejavamail.disable.all.clientvalidation</li>
4340
* <li>simplejavamail.custom.sslfactory.class</li>
4441
* <li>simplejavamail.proxy.host</li>
@@ -132,6 +129,7 @@ public enum Property {
132129
SMTP_PORT("simplejavamail.smtp.port"),
133130
SMTP_USERNAME("simplejavamail.smtp.username"),
134131
SMTP_PASSWORD("simplejavamail.smtp.password"),
132+
SMTP_OAUTH2_TOKEN("simplejavamail.smtp.oauth2token"),
135133
DISABLE_ALL_CLIENTVALIDATION("simplejavamail.disable.all.clientvalidation"),
136134
CUSTOM_SSLFACTORY_CLASS("simplejavamail.custom.sslfactory.class"),
137135
PROXY_HOST("simplejavamail.proxy.host"),

modules/core-test-module/src/main/java/demo/DemoAppBase.java

+12-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ public class DemoAppBase {
1818
// if you have 2-factor login turned on, you need to generate a once-per app password
1919
// https://security.google.com/settings/security/apppasswords
2020
private static final String YOUR_GMAIL_PASSWORD = "<your password>";
21-
21+
22+
// getting this token requires a few steps, listed here: https://github.com/bbottema/simple-java-mail/issues/421#issuecomment-1371010959
23+
private static final String YOUR_OAUTH2_TOKEN = "<your oauth2 token>";
24+
2225
/**
2326
* If you just want to see what email is being sent, just set this to true. It won't actually connect to an SMTP server then.
2427
*/
@@ -34,14 +37,17 @@ public class DemoAppBase {
3437
}
3538
}
3639

37-
static final MailerRegularBuilder<?> mailerSMTPBuilder = buildMailer("smtp.gmail.com", 25, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, TransportStrategy.SMTP);
38-
static final MailerRegularBuilder<?> mailerTLSBuilder = buildMailer("smtp.gmail.com", 587, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, TransportStrategy.SMTP_TLS);
39-
static final MailerRegularBuilder<?> mailerSSLBuilder = buildMailer("smtp.gmail.com", 465, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, TransportStrategy.SMTPS);
40+
static final MailerRegularBuilder<?> mailerSMTPBuilder = buildMailer("smtp.gmail.com", 25, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, null, TransportStrategy.SMTP);
41+
static final MailerRegularBuilder<?> mailerTLSBuilder = buildMailer("smtp.gmail.com", 587, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, null, TransportStrategy.SMTP_TLS);
42+
static final MailerRegularBuilder<?> mailerSSLBuilder = buildMailer("smtp.gmail.com", 465, YOUR_GMAIL_ADDRESS, YOUR_GMAIL_PASSWORD, null, TransportStrategy.SMTPS);
43+
static final MailerRegularBuilder<?> mailerOAuth2Builder = buildMailer("smtp.gmail.com", 587, YOUR_GMAIL_ADDRESS, null, YOUR_OAUTH2_TOKEN, TransportStrategy.SMTP_OAUTH2);
4044

4145
@SuppressWarnings("SameParameterValue")
42-
private static MailerRegularBuilder<?> buildMailer(String host, int port, String gMailAddress, String gMailPassword, TransportStrategy strategy) {
46+
private static MailerRegularBuilder<?> buildMailer(String host, int port, String gMailAddress, String gMailPassword, String oauth2token, TransportStrategy strategy) {
4347
return ImplLoader.loadMailerBuilder()
44-
.withSMTPServer(host, port, gMailAddress, gMailPassword)
48+
.withSMTPServer(host, port, gMailAddress)
49+
.withSMTPServerPassword(gMailPassword)
50+
.withSMTPOAuth2Token(oauth2token)
4551
.withTransportStrategy(strategy)
4652
.withTransportModeLoggingOnly(LOGGING_MODE)
4753
.clearProxy();

modules/simple-java-mail/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
<version>${project.version}</version>
3232
<scope>compile</scope>
3333
</dependency>
34+
<dependency>
35+
<groupId>org.simplejavamail</groupId>
36+
<artifactId>google-oauth2-provider</artifactId>
37+
<version>1.0.1</version>
38+
<scope>compile</scope>
39+
</dependency>
3440

3541
<!-- optional support modules -->
3642
<dependency>

modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/MailerException.java

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ class MailerException extends MailException {
1010

1111
static final String ERROR_READING_SMIME_FROM_INPUTSTREAM = "Was unable to read S/MIME data from input stream";
1212
static final String ERROR_READING_FROM_FILE = "Error reading from file: %s";
13+
static final String CANNOT_USE_BOTH_PASSWORD_AND_OAUTH2 = "Either authenticate using password or OAuth2 token, but not both";
14+
static final String MISSING_OAUTH2_TOKEN = "TransportStrategy is OAUTH2 but no OAUTH2 token provided";
15+
static final String WRONG_TRANSPORTSTRATEGY_FOR_OAUTH2_TOKEN = "OAUTH2 token provided, but TransportStrategy was %s instead of OAUTH2";
1316
static final String INVALID_PROXY_SLL_COMBINATION = "Proxy is not supported for SSL connections (this is a limitation by the underlying JavaMail framework)";
1417
static final String ERROR_CONNECTING_SMTP_SERVER = "Was unable to connect to SMTP server";
1518
static final String GENERIC_ERROR = "Failed to send email [%s], reason: Third party error";

0 commit comments

Comments
 (0)