Separate email preparation and email sending into separate classes
- SendMailSSL keeps on handling the technical details for sending mails, while EmailService offers methods to other classes and worries about generating the correct email content
This commit is contained in:
@@ -2,7 +2,7 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@@ -18,7 +18,7 @@ class TestEmailSender implements DebugSection {
|
||||
private DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
private SendMailSSL sendMailSSL;
|
||||
private EmailService emailService;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -33,7 +33,7 @@ class TestEmailSender implements DebugSection {
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, List<String> arguments) {
|
||||
if (!sendMailSSL.hasAllInformation()) {
|
||||
if (!emailService.hasAllInformation()) {
|
||||
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml " +
|
||||
"for sending emails. Please check your config.yml");
|
||||
return;
|
||||
@@ -43,7 +43,7 @@ class TestEmailSender implements DebugSection {
|
||||
|
||||
// getEmail() takes care of informing the sender of the error if email == null
|
||||
if (email != null) {
|
||||
boolean sendMail = sendMailSSL.sendTestEmail(email);
|
||||
boolean sendMail = emailService.sendTestEmail(email);
|
||||
if (sendMail) {
|
||||
sender.sendMessage("Test email sent to " + email + " with success");
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,7 @@ import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
@@ -37,7 +37,7 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private SendMailSSL sendMailSsl;
|
||||
private EmailService emailService;
|
||||
|
||||
@Inject
|
||||
private RecoveryCodeService recoveryCodeService;
|
||||
@@ -47,7 +47,7 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
final String playerMail = arguments.get(0);
|
||||
final String playerName = player.getName();
|
||||
|
||||
if (!sendMailSsl.hasAllInformation()) {
|
||||
if (!emailService.hasAllInformation()) {
|
||||
ConsoleLogger.warning("Mail API is not set");
|
||||
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||
return;
|
||||
@@ -84,7 +84,7 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
|
||||
private void createAndSendRecoveryCode(Player player, String email) {
|
||||
String recoveryCode = recoveryCodeService.generateCode(player.getName());
|
||||
boolean couldSendMail = sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode);
|
||||
boolean couldSendMail = emailService.sendRecoveryCode(player.getName(), email, recoveryCode);
|
||||
if (couldSendMail) {
|
||||
commonService.send(player, MessageKey.RECOVERY_CODE_SENT);
|
||||
} else {
|
||||
@@ -108,7 +108,7 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
HashedPassword hashNew = passwordSecurity.computeHash(thePass, name);
|
||||
|
||||
dataSource.updatePassword(name, hashNew);
|
||||
boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, thePass);
|
||||
boolean couldSendMail = emailService.sendPasswordMail(name, email, thePass);
|
||||
if (couldSendMail) {
|
||||
commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package fr.xephi.authme.command.executable.register;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.process.Management;
|
||||
import fr.xephi.authme.process.register.RegisterSecondaryArgument;
|
||||
@@ -37,7 +37,7 @@ public class RegisterCommand extends PlayerCommand {
|
||||
private CommonService commonService;
|
||||
|
||||
@Inject
|
||||
private SendMailSSL sendMailSsl;
|
||||
private EmailService emailService;
|
||||
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
@@ -127,7 +127,7 @@ public class RegisterCommand extends PlayerCommand {
|
||||
}
|
||||
|
||||
private void handleEmailRegistration(Player player, List<String> arguments) {
|
||||
if (!sendMailSsl.hasAllInformation()) {
|
||||
if (!emailService.hasAllInformation()) {
|
||||
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
|
||||
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package fr.xephi.authme.mail;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.initialization.DataFolder;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.FileUtils;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Creates emails and sends them.
|
||||
*/
|
||||
public class EmailService {
|
||||
|
||||
private final File dataFolder;
|
||||
private final String serverName;
|
||||
private final Settings settings;
|
||||
private final SendMailSSL sendMailSSL;
|
||||
|
||||
@Inject
|
||||
EmailService(@DataFolder File dataFolder, Server server, Settings settings, SendMailSSL sendMailSSL) {
|
||||
this.dataFolder = dataFolder;
|
||||
this.serverName = server.getServerName();
|
||||
this.settings = settings;
|
||||
this.sendMailSSL = sendMailSSL;
|
||||
}
|
||||
|
||||
public boolean hasAllInformation() {
|
||||
return sendMailSSL.hasAllInformation();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends an email to the user with his new password.
|
||||
*
|
||||
* @param name the name of the player
|
||||
* @param mailAddress the player's email
|
||||
* @param newPass the new password
|
||||
* @return true if email could be sent, false otherwise
|
||||
*/
|
||||
public boolean sendPasswordMail(String name, String mailAddress, String newPass) {
|
||||
if (!hasAllInformation()) {
|
||||
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
|
||||
return false;
|
||||
}
|
||||
|
||||
HtmlEmail email;
|
||||
try {
|
||||
email = sendMailSSL.initializeMail(mailAddress);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
|
||||
// Generate an image?
|
||||
File file = null;
|
||||
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
|
||||
try {
|
||||
file = generateImage(name, newPass);
|
||||
mailText = embedImageIntoEmailContent(file, email, mailText);
|
||||
} catch (IOException | EmailException e) {
|
||||
ConsoleLogger.logException(
|
||||
"Unable to send new password as image for email " + mailAddress + ":", e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean couldSendEmail = sendMailSSL.sendEmail(mailText, email);
|
||||
FileUtils.delete(file);
|
||||
return couldSendEmail;
|
||||
}
|
||||
|
||||
public boolean sendRecoveryCode(String name, String email, String code) {
|
||||
HtmlEmail htmlEmail;
|
||||
try {
|
||||
htmlEmail = sendMailSSL.initializeMail(email);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email for recovery code:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
|
||||
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
|
||||
return sendMailSSL.sendEmail(message, htmlEmail);
|
||||
}
|
||||
|
||||
public boolean sendTestEmail(String email) {
|
||||
HtmlEmail htmlEmail;
|
||||
try {
|
||||
htmlEmail = sendMailSSL.initializeMail(email);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email for sample email:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
htmlEmail.setSubject("AuthMe test email");
|
||||
String message = "Hello there!<br />This is a sample email sent to you from a Minecraft server ("
|
||||
+ serverName + ") via /authme debug mail. If you're seeing this, sending emails should be fine.";
|
||||
return sendMailSSL.sendEmail(message, htmlEmail);
|
||||
}
|
||||
|
||||
private File generateImage(String name, String newPass) throws IOException {
|
||||
ImageGenerator gen = new ImageGenerator(newPass);
|
||||
File file = new File(dataFolder, name + "_new_pass.jpg");
|
||||
ImageIO.write(gen.generateImage(), "jpg", file);
|
||||
return file;
|
||||
}
|
||||
|
||||
private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content)
|
||||
throws EmailException {
|
||||
DataSource source = new FileDataSource(image);
|
||||
String tag = email.embed(source, image.getName());
|
||||
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
||||
}
|
||||
|
||||
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
|
||||
return mailText
|
||||
.replace("<playername />", name)
|
||||
.replace("<servername />", serverName)
|
||||
.replace("<generatedpass />", newPass);
|
||||
}
|
||||
|
||||
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
|
||||
return mailText
|
||||
.replace("<playername />", name)
|
||||
.replace("<servername />", serverName)
|
||||
.replace("<recoverycode />", code)
|
||||
.replace("<hoursvalid />", String.valueOf(hoursValid));
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,17 @@
|
||||
package fr.xephi.authme.mail;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.initialization.DataFolder;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.FileUtils;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.apache.commons.mail.EmailConstants;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import javax.activation.CommandMap;
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.activation.MailcapCommandMap;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.mail.Session;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.Security;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -34,14 +24,10 @@ import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
|
||||
*/
|
||||
public class SendMailSSL {
|
||||
|
||||
private final File dataFolder;
|
||||
private final String serverName;
|
||||
private final Settings settings;
|
||||
|
||||
@Inject
|
||||
SendMailSSL(@DataFolder File dataFolder, Server server, Settings settings) {
|
||||
this.dataFolder = dataFolder;
|
||||
this.serverName = server.getServerName();
|
||||
SendMailSSL(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@@ -55,91 +41,7 @@ public class SendMailSSL {
|
||||
&& !settings.getProperty(MAIL_PASSWORD).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email to the user with his new password.
|
||||
*
|
||||
* @param name the name of the player
|
||||
* @param mailAddress the player's email
|
||||
* @param newPass the new password
|
||||
* @return true if email could be sent, false otherwise
|
||||
*/
|
||||
public boolean sendPasswordMail(String name, String mailAddress, String newPass) {
|
||||
if (!hasAllInformation()) {
|
||||
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
|
||||
return false;
|
||||
}
|
||||
|
||||
HtmlEmail email;
|
||||
try {
|
||||
email = initializeMail(mailAddress);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
|
||||
// Generate an image?
|
||||
File file = null;
|
||||
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
|
||||
try {
|
||||
file = generateImage(name, newPass);
|
||||
mailText = embedImageIntoEmailContent(file, email, mailText);
|
||||
} catch (IOException | EmailException e) {
|
||||
ConsoleLogger.logException(
|
||||
"Unable to send new password as image for email " + mailAddress + ":", e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean couldSendEmail = sendEmail(mailText, email);
|
||||
FileUtils.delete(file);
|
||||
return couldSendEmail;
|
||||
}
|
||||
|
||||
public boolean sendRecoveryCode(String name, String email, String code) {
|
||||
HtmlEmail htmlEmail;
|
||||
try {
|
||||
htmlEmail = initializeMail(email);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email for recovery code:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
|
||||
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
|
||||
return sendEmail(message, htmlEmail);
|
||||
}
|
||||
|
||||
public boolean sendTestEmail(String email) {
|
||||
HtmlEmail htmlEmail;
|
||||
try {
|
||||
htmlEmail = initializeMail(email);
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email for sample email:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
htmlEmail.setSubject("AuthMe test email");
|
||||
String message = "Hello there!<br />This is a sample email sent to you from a Minecraft server ("
|
||||
+ serverName + ") via /authme debug mail. If you're seeing this, sending emails should be fine.";
|
||||
return sendEmail(message, htmlEmail);
|
||||
}
|
||||
|
||||
private File generateImage(String name, String newPass) throws IOException {
|
||||
ImageGenerator gen = new ImageGenerator(newPass);
|
||||
File file = new File(dataFolder, name + "_new_pass.jpg");
|
||||
ImageIO.write(gen.generateImage(), "jpg", file);
|
||||
return file;
|
||||
}
|
||||
|
||||
private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content)
|
||||
throws EmailException {
|
||||
DataSource source = new FileDataSource(image);
|
||||
String tag = email.embed(source, image.getName());
|
||||
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
||||
public HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
||||
String senderMail = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_ADDRESS))
|
||||
? settings.getProperty(EmailSettings.MAIL_ACCOUNT)
|
||||
: settings.getProperty(EmailSettings.MAIL_ADDRESS);
|
||||
@@ -163,8 +65,7 @@ public class SendMailSSL {
|
||||
return email;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean sendEmail(String content, HtmlEmail email) {
|
||||
public boolean sendEmail(String content, HtmlEmail email) {
|
||||
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader());
|
||||
// Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative
|
||||
// cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type
|
||||
@@ -191,21 +92,6 @@ public class SendMailSSL {
|
||||
}
|
||||
}
|
||||
|
||||
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
|
||||
return mailText
|
||||
.replace("<playername />", name)
|
||||
.replace("<servername />", serverName)
|
||||
.replace("<generatedpass />", newPass);
|
||||
}
|
||||
|
||||
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
|
||||
return mailText
|
||||
.replace("<playername />", name)
|
||||
.replace("<servername />", serverName)
|
||||
.replace("<recoverycode />", code)
|
||||
.replace("<hoursvalid />", String.valueOf(hoursValid));
|
||||
}
|
||||
|
||||
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
|
||||
switch (port) {
|
||||
case 587:
|
||||
|
||||
+4
-4
@@ -2,7 +2,7 @@ package fr.xephi.authme.process.register.executors;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.process.SyncProcessManager;
|
||||
@@ -15,8 +15,8 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
||||
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
|
||||
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
||||
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ class EmailRegisterExecutorProvider {
|
||||
private CommonService commonService;
|
||||
|
||||
@Inject
|
||||
private SendMailSSL sendMailSsl;
|
||||
private EmailService emailService;
|
||||
|
||||
@Inject
|
||||
private SyncProcessManager syncProcessManager;
|
||||
@@ -80,7 +80,7 @@ class EmailRegisterExecutorProvider {
|
||||
|
||||
@Override
|
||||
public void executePostPersistAction() {
|
||||
boolean couldSendMail = sendMailSsl.sendPasswordMail(player.getName(), email, password);
|
||||
boolean couldSendMail = emailService.sendPasswordMail(player.getName(), email, password);
|
||||
if (couldSendMail) {
|
||||
syncProcessManager.processSyncEmailRegister(player);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user