Skip to content

Commit

Permalink
Added specific SMTP connection for OTP emails (#10) (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
karthik-tarento authored Sep 12, 2024
1 parent f8a98ed commit 753401b
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 4 deletions.
5 changes: 4 additions & 1 deletion controller/app/util/ACTORS.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.sunbird.actor.notes.NotesManagementActor;
import org.sunbird.actor.notification.BackGroundNotificationActor;
import org.sunbird.actor.notification.EmailServiceActor;
import org.sunbird.actor.notification.OTPEmailServiceActor;
import org.sunbird.actor.notification.SendNotificationActor;
import org.sunbird.actor.organisation.OrganisationBackgroundActor;
import org.sunbird.actor.organisation.OrganisationManagementActor;
Expand Down Expand Up @@ -101,7 +102,9 @@ public enum ACTORS {
USER_TNC_ACTOR(UserTnCActor.class, "user_tnc_actor"),
USER_TYPE_ACTOR(UserTypeActor.class, "user_type_actor"),
USER_UPDATE_ACTOR(UserUpdateActor.class, "user_update_actor"),
BACKGROUND_JOB_MANAGER_ACTOR(BackgroundJobManager.class, "background_job_manager_actor");
BACKGROUND_JOB_MANAGER_ACTOR(BackgroundJobManager.class, "background_job_manager_actor"),
// OTP Notification Actor
OTP_EMAIL_SERVICE_ACTOR(OTPEmailServiceActor.class, "otp_email_service_actor"),;

ACTORS(Class clazz, String name) {
actorClass = clazz;
Expand Down
10 changes: 10 additions & 0 deletions controller/conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ akka {
{
dispatcher = akka.actor.notification-dispatcher
}
"/otp_email_service_actor"
{
router = smallest-mailbox-pool
nr-of-instances = 5
dispatcher = notification-dispatcher
}
"/otp_email_service_actor/*"
{
dispatcher = akka.actor.notification-dispatcher
}
"/user_profile_read_actor"
{
router = smallest-mailbox-pool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,5 +659,12 @@ public final class JsonKey {
public static final String MENTORING = "mentoring";
public static final String USERID= "userid";
public static final String NETCORE = "NetCore";
public static final String OTP_EMAIL_SERVER_HOST = "sunbird_otp_mail_server_host";
public static final String OTP_EMAIL_SERVER_PASSWORD = "sunbird_otp_mail_server_password";
public static final String OTP_EMAIL_SERVER_PORT = "sunbird_otp_mail_server_port";
public static final String OTP_EMAIL_SERVER_USERNAME = "sunbird_otp_mail_server_username";
public static final String OTP_EMAIL_SERVER_FROM = "sunbird_otp_mail_server_from_email";
public static final String OTP_EMAIL_PROTOCOL = "sunbird_otp_mail_protocol";

private JsonKey() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.sunbird.mail;

import java.util.Properties;

import javax.mail.Session;
import javax.mail.Transport;

import org.apache.commons.lang3.StringUtils;
import org.sunbird.keys.JsonKey;
import org.sunbird.logging.LoggerUtil;
import org.sunbird.request.RequestContext;
import org.sunbird.util.PropertiesCache;

public class OTPSendGridConnection {
public final LoggerUtil logger = new LoggerUtil(OTPSendGridConnection.class);

private Properties props = null;
private String host;

private String port;

private String userName;
private String password;
private String fromEmail;
private Session session;
private Transport transport;
private String emailProtocol;

public Transport createConnection(RequestContext context) {
try {
host = System.getenv(JsonKey.OTP_EMAIL_SERVER_HOST);
port = System.getenv(JsonKey.OTP_EMAIL_SERVER_PORT);
userName = System.getenv(JsonKey.OTP_EMAIL_SERVER_USERNAME);
password = System.getenv(JsonKey.OTP_EMAIL_SERVER_PASSWORD);
fromEmail = System.getenv(JsonKey.OTP_EMAIL_SERVER_FROM);
emailProtocol = System.getenv(JsonKey.OTP_EMAIL_PROTOCOL);

if (StringUtils.isBlank(host)
|| StringUtils.isBlank(port)
|| StringUtils.isBlank(userName)
|| StringUtils.isBlank(password)
|| StringUtils.isBlank(fromEmail)) {
logger.info(
context,
"Email setting value is not provided by Env variable=="
+ host
+ " "
+ port
+ " "
+ fromEmail);
initialiseFromProperty();
}

props = System.getProperties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.socketFactory.port", port);

props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", port);

props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.ssl.protocols", emailProtocol);

session = Session.getInstance(props, new GMailAuthenticator(userName, password));
transport = session.getTransport("smtp");
transport.connect(host, userName, password);
return transport;
} catch (Exception e) {
logger.error(
context, "Exception occurred while smtp session and creating transport connection", e);
}
return null;
}

public Session getSession() {
return session;
}

public void setSession(Session session) {
this.session = session;
}

public Transport getTransport() {
return transport;
}

public void initialiseFromProperty() {
host = PropertiesCache.getInstance().getProperty(JsonKey.OTP_EMAIL_SERVER_HOST);
port = PropertiesCache.getInstance().getProperty(JsonKey.OTP_EMAIL_SERVER_PORT);
userName = PropertiesCache.getInstance().getProperty(JsonKey.OTP_EMAIL_SERVER_USERNAME);
password = PropertiesCache.getInstance().getProperty(JsonKey.OTP_EMAIL_SERVER_PASSWORD);
fromEmail = PropertiesCache.getInstance().getProperty(JsonKey.OTP_EMAIL_SERVER_FROM);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package org.sunbird.actor.notification;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.sunbird.actor.core.BaseActor;
import org.sunbird.keys.JsonKey;
import org.sunbird.logging.LoggerUtil;
import org.sunbird.mail.SendEmail;
import org.sunbird.mail.OTPSendGridConnection;
import org.sunbird.operations.ActorOperations;
import org.sunbird.request.Request;
import org.sunbird.request.RequestContext;
import org.sunbird.response.Response;
import org.sunbird.service.notification.NotificationService;
import org.sunbird.util.ProjectUtil;

public class OTPEmailServiceActor extends BaseActor {
public final LoggerUtil logger = new LoggerUtil(EmailServiceActor.class);
private final NotificationService notificationService = new NotificationService();
private final OTPSendGridConnection connection = new OTPSendGridConnection();
private final String resetInterval =
ProjectUtil.getConfigValue("sendgrid_connection_reset_interval");
private volatile long timer;

@Override
public void onReceive(Request request) throws Throwable {
if (null == connection.getTransport()) {
connection.createConnection(request.getRequestContext());
// set timer value
timer = System.currentTimeMillis();
}
if (request.getOperation().equalsIgnoreCase(ActorOperations.EMAIL_SERVICE.getValue())) {
sendMail(request);
} else {
onReceiveUnsupportedOperation();
}
}

private void sendMail(Request actorMessage) {
RequestContext requestContext = actorMessage.getRequestContext();
Map<String, Object> request =
(Map<String, Object>) actorMessage.getRequest().get(JsonKey.EMAIL_REQUEST);
List<String> userIds =
(CollectionUtils.isEmpty((List<String>) request.get(JsonKey.RECIPIENT_USERIDS)))
? new ArrayList<>()
: (List<String>) request.get(JsonKey.RECIPIENT_USERIDS);
List<String> phones =
(CollectionUtils.isEmpty((List<String>) request.get(JsonKey.RECIPIENT_PHONES)))
? new ArrayList<>()
: (List<String>) request.get(JsonKey.RECIPIENT_PHONES);
List<String> emails =
(CollectionUtils.isEmpty((List<String>) request.get(JsonKey.RECIPIENT_EMAILS)))
? new ArrayList<>()
: (List<String>) request.get(JsonKey.RECIPIENT_EMAILS);
String mode;
if (request.get(JsonKey.MODE) != null
&& JsonKey.SMS.equalsIgnoreCase((String) request.get(JsonKey.MODE))) {
mode = JsonKey.SMS;
} else {
mode = JsonKey.EMAIL;
}
if (JsonKey.SMS.equalsIgnoreCase(mode)) {
notificationService.processSMS(
userIds, phones, (String) request.get(JsonKey.BODY), requestContext);
}

if (JsonKey.EMAIL.equalsIgnoreCase(mode)) {
// Fetch user emails from Elastic Search based on recipient search query given in
// request.
Map<String, Object> recipientSearchQuery =
(Map<String, Object>) request.get(JsonKey.RECIPIENT_SEARCH_QUERY);
List<String> emailList =
notificationService.validateAndGetEmailList(
userIds, emails, recipientSearchQuery, requestContext);
notificationService.updateFirstNameAndOrgNameInEmailContext(
userIds, emailList, request, requestContext);

if (CollectionUtils.isNotEmpty(emailList)) {
String template =
notificationService.getEmailTemplateFile(
(String) request.get(JsonKey.EMAIL_TEMPLATE_TYPE), requestContext);
sendMail(request, emailList, template, requestContext);
}
}

Response res = new Response();
res.put(JsonKey.RESPONSE, JsonKey.SUCCESS);
sender().tell(res, self());
}

private void sendMail(
Map<String, Object> request,
List<String> emails,
String template,
RequestContext requestContext) {
long startTime = System.currentTimeMillis();
try {
SendEmail sendEmail = new SendEmail();
Velocity.init();
VelocityContext context = ProjectUtil.getContext(request);
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "SimpleVelocity", template);
long interval = 60000L;
if (StringUtils.isNotBlank(resetInterval)) {
interval = Long.parseLong(resetInterval);
}
if (null == connection.getTransport()
|| ((System.currentTimeMillis()) - timer >= interval)
|| (!connection.getTransport().isConnected())) {
resetConnection(requestContext);
}
sendEmail.send(
emails.toArray(new String[emails.size()]),
(String) request.get(JsonKey.SUBJECT),
context,
writer,
connection.getSession(),
connection.getTransport());
} catch (Exception e) {
logger.error(
requestContext,
"EmailServiceActor:sendMail: Exception occurred with message = " + e.getMessage(),
e);
}
logger.info("Email Sent. Time taken (in ms): " + (System.currentTimeMillis() - startTime));
}

private void resetConnection(RequestContext context) {
logger.info(
context,
"EmailServiceActor:resetConnection : SMTP Transport client connection is closed or timed out. Create new connection.");
connection.createConnection(context);
// set timer value
timer = System.currentTimeMillis();
}
}
6 changes: 3 additions & 3 deletions service/src/main/java/org/sunbird/actor/otp/SendOTPActor.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class SendOTPActor extends BaseActor {
private final LogMaskServiceImpl logMaskService = new LogMaskServiceImpl();

@Inject
@Named("email_service_actor")
private ActorRef emailServiceActor;
@Named("otp_email_service_actor")
private ActorRef otpEmailServiceActor;

@Override
public void onReceive(Request request) throws Throwable {
Expand Down Expand Up @@ -80,7 +80,7 @@ private void sendOTPViaEmail(String key, String otp, String templateId, RequestC
"SendOTPActor:sendOTPViaEmail : Calling EmailServiceActor for Key = "
+ logMaskService.maskEmail(key));
try {
emailServiceActor.tell(emailRequest, self());
otpEmailServiceActor.tell(emailRequest, self());
} catch (Exception ex) {
logger.error(context, "Exception while sending OTP via email", ex);
}
Expand Down

0 comments on commit 753401b

Please sign in to comment.