View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.tools;
12  
13  import jakarta.activation.DataHandler;
14  import jakarta.activation.DataSource;
15  import jakarta.mail.Message;
16  import jakarta.mail.MessagingException;
17  import jakarta.mail.Part;
18  import jakarta.mail.Session;
19  import jakarta.mail.Transport;
20  import jakarta.mail.internet.AddressException;
21  import jakarta.mail.internet.InternetAddress;
22  import jakarta.mail.internet.MimeBodyPart;
23  import jakarta.mail.internet.MimeMessage;
24  import jakarta.mail.internet.MimeMultipart;
25  
26  import java.io.PrintStream;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.List;
30  import java.util.Properties;
31  
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  import org.springframework.beans.factory.annotation.Value;
35  
36  /**
37   * Facade for sending emails with the JavaMail API.
38   */
39  public class Mailer {
40  
41    /** The Constant PROPERTY_KEY_SMTP. */
42    public static final String PROPERTY_KEY_SMTP = "mail.smtp.host";
43  
44    /** The Constant logger. */
45    private static final Logger logger = LoggerFactory.getLogger(Mailer.class);
46  
47    /** The from. */
48    private String from;
49  
50    /** The smtp. */
51    private String smtp;
52  
53    /** The default to. */
54    private String defaultTo;
55  
56    /** The subject prefix. */
57    private String subjectPrefix;
58  
59    /**
60     * Instantiates a new mailer.
61     */
62    public Mailer() {
63      this(null);
64    }
65  
66    /**
67     * Instantiates a new mailer.
68     *
69     * @param from the from
70     */
71    public Mailer(String from) {
72      this(from, null);
73    }
74  
75    /**
76     * Instantiates a new mailer.
77     *
78     * @param from the from
79     * @param smtp the smtp
80     */
81    public Mailer(String from, String smtp) {
82      this.smtp = smtp;
83      this.from = from;
84    }
85  
86    /**
87     * Gets the from.
88     *
89     * @return the from
90     */
91    public String getFrom() {
92      return from;
93    }
94  
95    /**
96     * Gets the smtp.
97     *
98     * @return the smtp
99     */
100   public String getSmtp() {
101     if (smtp == null) {
102       return System.getProperty(PROPERTY_KEY_SMTP);
103     }
104     return smtp;
105   }
106 
107   /**
108    * Sets the from.
109    *
110    * @param from the new from
111    */
112   public void setFrom(String from) {
113     this.from = from;
114   }
115 
116   /**
117    * Sets the smtp.
118    *
119    * @param smtp the new smtp
120    */
121   public void setSmtp(String smtp) {
122     this.smtp = smtp;
123   }
124 
125   /**
126    * Gets the default to.
127    *
128    * @return the default to
129    */
130   public String getDefaultTo() {
131     return defaultTo;
132   }
133 
134   /**
135    * Sets the default to.
136    *
137    * @param defaultTo the new default to
138    */
139   @Value("${psiprobe.tools.mail.to}")
140   public void setDefaultTo(String defaultTo) {
141     this.defaultTo = defaultTo;
142   }
143 
144   /**
145    * Gets the subject prefix.
146    *
147    * @return the subject prefix
148    */
149   public String getSubjectPrefix() {
150     return subjectPrefix;
151   }
152 
153   /**
154    * Sets the subject prefix.
155    *
156    * @param subjectPrefix the new subject prefix
157    */
158   @Value("${psiprobe.tools.mail.subjectPrefix}")
159   public void setSubjectPrefix(String subjectPrefix) {
160     this.subjectPrefix = subjectPrefix;
161   }
162 
163   /**
164    * Send.
165    *
166    * @param mailMessage the mail message
167    *
168    * @throws MessagingException the messaging exception
169    */
170   public void send(MailMessage mailMessage) throws MessagingException {
171     Properties props = (Properties) System.getProperties().clone();
172     if (smtp != null) {
173       props.put(PROPERTY_KEY_SMTP, smtp);
174     }
175 
176     try (PrintStream debugOut =
177         LogOutputStream.createPrintStream(logger, LogOutputStream.LEVEL_DEBUG)) {
178       Session session = Session.getDefaultInstance(props);
179       session.setDebug(true);
180       session.setDebugOut(debugOut);
181 
182       MimeMessage message = createMimeMessage(session, mailMessage);
183       logger.debug("Sending message");
184       Transport.send(message);
185     }
186   }
187 
188   /**
189    * Creates the mime message.
190    *
191    * @param session the session
192    * @param mailMessage the mail message
193    *
194    * @return the mime message
195    *
196    * @throws MessagingException the messaging exception
197    */
198   private MimeMessage createMimeMessage(Session session, MailMessage mailMessage)
199       throws MessagingException {
200 
201     String subject = mailMessage.getSubject();
202     if (subjectPrefix != null && !subjectPrefix.isEmpty()) {
203       subject = subjectPrefix + " " + subject;
204     }
205 
206     MimeMultipart content = new MimeMultipart("related");
207 
208     // Create attachments
209     DataSource[] attachments = mailMessage.getAttachmentsArray();
210     for (DataSource attachment : attachments) {
211       MimeBodyPart attachmentPart = createAttachmentPart(attachment);
212       content.addBodyPart(attachmentPart);
213     }
214 
215     // Create message body
216     MimeBodyPart bodyPart = createMessageBodyPart(mailMessage.getBody(), mailMessage.isBodyHtml());
217     content.addBodyPart(bodyPart);
218 
219     MimeMessage message = new MimeMessage(session);
220     if (from == null) {
221       // Uses mail.from property
222       message.setFrom();
223     } else {
224       message.setFrom(new InternetAddress(from));
225     }
226 
227     InternetAddress[] to = createAddresses(mailMessage.getToArray());
228     if (to.length == 0) {
229       to = InternetAddress.parse(defaultTo);
230     }
231     message.setRecipients(Message.RecipientType.TO, to);
232 
233     InternetAddress[] cc = createAddresses(mailMessage.getCcArray());
234     message.setRecipients(Message.RecipientType.CC, cc);
235 
236     InternetAddress[] bcc = createAddresses(mailMessage.getBccArray());
237     message.setRecipients(Message.RecipientType.BCC, bcc);
238 
239     message.setSubject(subject);
240     message.setContent(content);
241     return message;
242   }
243 
244   /**
245    * Creates the addresses.
246    *
247    * @param addresses the addresses
248    *
249    * @return the Internet address[]
250    *
251    * @throws AddressException the address exception
252    */
253   private static InternetAddress[] createAddresses(String[] addresses) throws AddressException {
254     List<InternetAddress> result = new ArrayList<>(addresses.length);
255     for (String address : addresses) {
256       InternetAddress[] parsedAddresses = InternetAddress.parse(address);
257       result.addAll(Arrays.asList(parsedAddresses));
258     }
259     return result.toArray(new InternetAddress[result.size()]);
260   }
261 
262   /**
263    * Creates the attachment part.
264    *
265    * @param attachment the attachment
266    *
267    * @return the mime body part
268    *
269    * @throws MessagingException the messaging exception
270    */
271   private static MimeBodyPart createAttachmentPart(DataSource attachment)
272       throws MessagingException {
273 
274     MimeBodyPart attachmentPart = new MimeBodyPart();
275     attachmentPart.setDataHandler(new DataHandler(attachment));
276     attachmentPart.setDisposition(Part.ATTACHMENT);
277     attachmentPart.setFileName(attachment.getName());
278     return attachmentPart;
279   }
280 
281   /**
282    * Creates the message body part.
283    *
284    * @param body the body
285    * @param html the html
286    *
287    * @return the mime body part
288    *
289    * @throws MessagingException the messaging exception
290    */
291   private static MimeBodyPart createMessageBodyPart(String body, boolean html)
292       throws MessagingException {
293     MimeBodyPart bodyPart = new MimeBodyPart();
294     bodyPart.setText(body);
295     bodyPart.setHeader("content-type", html ? "text/html" : "text/plain");
296     return bodyPart;
297   }
298 
299 }