1 /** 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * <p>http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * <p>Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 * express or implied. See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 package com.android.vts.util; 15 16 import com.android.vts.entity.UserFavoriteEntity; 17 import com.google.appengine.api.datastore.DatastoreService; 18 import com.google.appengine.api.datastore.DatastoreServiceFactory; 19 import com.google.appengine.api.datastore.Entity; 20 import com.google.appengine.api.datastore.Key; 21 import com.google.appengine.api.datastore.Query; 22 import com.google.appengine.api.datastore.Query.Filter; 23 import com.google.appengine.api.datastore.Query.FilterOperator; 24 import com.google.appengine.api.datastore.Query.FilterPredicate; 25 import java.io.IOException; 26 import java.io.UnsupportedEncodingException; 27 import java.util.ArrayList; 28 import java.util.HashSet; 29 import java.util.List; 30 import java.util.Properties; 31 import java.util.Set; 32 import java.util.logging.Level; 33 import java.util.logging.Logger; 34 import javax.mail.Message; 35 import javax.mail.MessagingException; 36 import javax.mail.Session; 37 import javax.mail.Transport; 38 import javax.mail.internet.InternetAddress; 39 import javax.mail.internet.MimeMessage; 40 import org.apache.commons.lang.StringUtils; 41 42 /** EmailHelper, a helper class for building and sending emails. */ 43 public class EmailHelper { 44 protected static final Logger logger = Logger.getLogger(EmailHelper.class.getName()); 45 protected static final String DEFAULT_EMAIL = System.getProperty("DEFAULT_EMAIL"); 46 protected static final String EMAIL_DOMAIN = System.getProperty("EMAIL_DOMAIN"); 47 protected static final String SENDER_EMAIL = System.getProperty("SENDER_EMAIL"); 48 private static final String VTS_EMAIL_NAME = "VTS Alert Bot"; 49 50 /** 51 * Fetches the list of subscriber email addresses for a test. 52 * 53 * @param testKey The key for the test for which to fetch the email addresses. 54 * @returns List of email addresses (String). 55 * @throws IOException 56 */ getSubscriberEmails(Key testKey)57 public static List<String> getSubscriberEmails(Key testKey) throws IOException { 58 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 59 Filter testFilter = 60 new FilterPredicate(UserFavoriteEntity.TEST_KEY, FilterOperator.EQUAL, testKey); 61 Query favoritesQuery = new Query(UserFavoriteEntity.KIND).setFilter(testFilter); 62 Set<String> emailSet = new HashSet<>(); 63 if (!StringUtils.isBlank(DEFAULT_EMAIL)) { 64 emailSet.add(DEFAULT_EMAIL); 65 } 66 for (Entity favorite : datastore.prepare(favoritesQuery).asIterable()) { 67 UserFavoriteEntity favoriteEntity = UserFavoriteEntity.fromEntity(favorite); 68 if (favoriteEntity != null && favoriteEntity.user != null 69 && favoriteEntity.user.getEmail().endsWith(EMAIL_DOMAIN)) { 70 emailSet.add(favoriteEntity.user.getEmail()); 71 } 72 } 73 return new ArrayList<>(emailSet); 74 } 75 76 /** 77 * Sends an email to the specified email address to notify of a test status change. 78 * 79 * @param emails List of subscriber email addresses (byte[]) to which the email should be sent. 80 * @param subject The email subject field, string. 81 * @param body The html (string) body to send in the email. 82 * @returns The Message object to be sent. 83 * @throws MessagingException, UnsupportedEncodingException 84 */ composeEmail(List<String> emails, String subject, String body)85 public static Message composeEmail(List<String> emails, String subject, String body) 86 throws MessagingException, UnsupportedEncodingException { 87 if (emails.size() == 0) { 88 throw new MessagingException("No subscriber email addresses provided"); 89 } 90 Properties props = new Properties(); 91 Session session = Session.getDefaultInstance(props, null); 92 93 Message msg = new MimeMessage(session); 94 for (String email : emails) { 95 try { 96 msg.addRecipient(Message.RecipientType.TO, new InternetAddress(email, email)); 97 } catch (MessagingException | UnsupportedEncodingException e) { 98 // Gracefully continue when a subscriber email is invalid. 99 logger.log(Level.WARNING, "Error sending email to recipient " + email + " : ", e); 100 } 101 } 102 msg.setFrom(new InternetAddress(SENDER_EMAIL, VTS_EMAIL_NAME)); 103 msg.setSubject(subject); 104 msg.setContent(body, "text/html; charset=utf-8"); 105 return msg; 106 } 107 108 /** 109 * Sends an email. 110 * 111 * @param msg Message object to send. 112 * @returns true if the message sends successfully, false otherwise 113 */ send(Message msg)114 public static boolean send(Message msg) { 115 try { 116 Transport.send(msg); 117 } catch (MessagingException e) { 118 logger.log(Level.WARNING, "Error sending email : ", e); 119 return false; 120 } 121 return true; 122 } 123 124 /** 125 * Sends a list of emails and logs any failures. 126 * 127 * @param messages List of Message objects to be sent. 128 */ sendAll(List<Message> messages)129 public static void sendAll(List<Message> messages) { 130 for (Message msg : messages) { 131 send(msg); 132 } 133 } 134 135 /** 136 * Sends an email. 137 * 138 * @param recipients List of email address strings to which an email will be sent. 139 * @param subject The subject of the email. 140 * @param body The body of the email. 141 * @returns true if the message sends successfully, false otherwise 142 */ send(List<String> recipients, String subject, String body)143 public static boolean send(List<String> recipients, String subject, String body) { 144 try { 145 Message msg = composeEmail(recipients, subject, body); 146 return send(msg); 147 } catch (MessagingException | UnsupportedEncodingException e) { 148 logger.log(Level.WARNING, "Error composing email : ", e); 149 return false; 150 } 151 } 152 } 153