package report; import com.sun.mail.util.MailConnectException; import dao.MarkingProperties; import dao.ResultDAO; import io.github.resilience4j.core.IntervalFunction; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryConfig; import io.github.resilience4j.retry.RetryRegistry; import jakarta.activation.FileDataSource; import jakarta.mail.AuthenticationFailedException; import java.awt.Window; import java.net.ConnectException; import javax.swing.JOptionPane; import javax.swing.JPasswordField; import model.Student; import org.simplejavamail.MailException; import org.simplejavamail.api.email.Email; import org.simplejavamail.api.mailer.Mailer; import org.simplejavamail.api.mailer.config.TransportStrategy; import org.simplejavamail.email.EmailBuilder; import org.simplejavamail.mailer.MailerBuilder; import static report.TimeStamp.getTimeStamp; import ui.BatchMailer; /** * * @author Mark George <mark.george@otago.ac.nz> */ public class SendReport { private static String password = null; private static Window parent; public SendReport(Window parent) { SendReport.parent = parent; } public Boolean sendReport(Student student, String reportFileName, Boolean batch) throws AuthenticationFailedException, ConnectException { String assessment = MarkingProperties.assessmentDescription(); String file = MarkingProperties.attachmentEmailName(); String mName = MarkingProperties.markerName(); String mEmail = MarkingProperties.markerEmail(); String ccEmail = MarkingProperties.ccEmail(); String mCode = MarkingProperties.paperCode(); String message = "Hi " + student.getFirstName() + ".\n" + "\n" + "Here is our feedback from marking your " + mCode + " " + assessment + " submission. The feedback is in the attached PDF document.\n" + "\n" + "Cheers,\n" + mName; Email email = EmailBuilder.startingBlank() .from(mName, mEmail) .to(student.getEmail()) .cc(ccEmail) .withSubject(mCode + " " + assessment + " Result") .withPlainText(message) .withAttachment(file, new FileDataSource(reportFileName)) .buildEmail(); try { String userName = MarkingProperties.smtpUserName(); if (password == null && userName != null) { String result = getPassword("Staff E-Mail Password"); if (result != null) { password = result; } else { System.out.println("Cancelled"); return false; } } TransportStrategy transport = TransportStrategy.SMTP; if (MarkingProperties.isTls()) { transport = TransportStrategy.SMTP_TLS; } RetryConfig cfg = RetryConfig.custom() .maxAttempts(10) .failAfterMaxAttempts(true) .intervalFunction(IntervalFunction.ofExponentialBackoff(5000, 2)) .build(); RetryRegistry registry = RetryRegistry.of(cfg); Retry retry = registry.retry("mailer"); if (parent instanceof BatchMailer bm) { Retry.EventPublisher eventPublisher = retry.getEventPublisher(); eventPublisher.onRetry(event -> bm.addMessage(getTimeStamp() + " - Retry " + event.getNumberOfRetryAttempts() + " of " + cfg.getMaxAttempts())); eventPublisher.onSuccess(event -> bm.addMessage(getTimeStamp() + " - Retry succeeded: ")); eventPublisher.onEvent(event -> bm.addMessage(event.getLastThrowable().getCause().getClass().getName())); } Mailer mailer = MailerBuilder .withSMTPServer(MarkingProperties.smtpHost(), MarkingProperties.smtpPort(), userName, password) .withTransportStrategy(transport) .buildMailer(); try { mailer.testConnection(); } catch (MailException ex) { if (ex.getCause() instanceof AuthenticationFailedException) { JOptionPane.showMessageDialog(parent, "Authentication Failed!"); password = null; throw new AuthenticationFailedException(); } else if (ex.getCause() instanceof MailConnectException) { JOptionPane.showMessageDialog(parent, "Could not connect to SMTP server!"); throw new ConnectException("Could not connect to server. Check smtp.host in properties file."); } } if (parent instanceof BatchMailer bm) { bm.addMessage(getTimeStamp() + " - " + student.getUsername()); } retry.executeRunnable(() -> { mailer.sendMail(email); }); new ResultDAO().mailSent(student); } catch (MailException ex) { if (!batch) { password = null; } if (parent instanceof BatchMailer bm) { bm.addMessage(getTimeStamp() + " - RETRIES EXCEEDED!"); } throw new SendException(ex); } return true; } public static String getPassword(String prompt) { JPasswordField txtPasswd = new JPasswordField(); int resp = JOptionPane.showConfirmDialog(parent, txtPasswd, prompt, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (resp == JOptionPane.OK_OPTION) { return new String(txtPasswd.getPassword()); } return null; } }