Index: trunk/src/integration-test/groovy/com/lemans/auth/EmailServiceIntegrationSpec.groovy =================================================================== diff -u -r8568 -r8936 --- trunk/src/integration-test/groovy/com/lemans/auth/EmailServiceIntegrationSpec.groovy (.../EmailServiceIntegrationSpec.groovy) (revision 8568) +++ trunk/src/integration-test/groovy/com/lemans/auth/EmailServiceIntegrationSpec.groovy (.../EmailServiceIntegrationSpec.groovy) (revision 8936) @@ -29,7 +29,7 @@ def setup() { dumbster.reset() } - @SuppressWarnings('LineLength') + @SuppressWarnings('LineLength') def 'can send a welcome email to a new ServiceProvider user'() { when: emailService.sendProviderWelcomeEmail(firstName, lastName, newPass, email) @@ -152,6 +152,7 @@ msg.body.contains 'Welcome Richard Feynman,' msg.body.contains SET_PASSWORD_URI msg.body.contains RESET_PASSWORD_URI + msg.body.contains 'name=test1.pdf' } private split(String s) { s.split(',')*.trim() } Index: trunk/src/test/18/test1.pdf =================================================================== diff -u --- trunk/src/test/18/test1.pdf (revision 0) +++ trunk/src/test/18/test1.pdf (revision 8936) @@ -0,0 +1 @@ \ No newline at end of file Index: trunk/grails-app/services/com/lemans/auth/EmailService.groovy =================================================================== diff -u -r8568 -r8936 --- trunk/grails-app/services/com/lemans/auth/EmailService.groovy (.../EmailService.groovy) (revision 8568) +++ trunk/grails-app/services/com/lemans/auth/EmailService.groovy (.../EmailService.groovy) (revision 8936) @@ -5,53 +5,63 @@ import org.apache.commons.validator.routines.EmailValidator import org.springframework.mail.javamail.MimeMessageHelper +import javax.activation.DataHandler +import javax.activation.FileDataSource +import javax.annotation.Resource +import javax.mail.BodyPart +import javax.mail.Multipart import javax.mail.internet.InternetAddress +import javax.mail.internet.MimeBodyPart import javax.mail.internet.MimeMessage import javax.mail.internet.MimeMessage.RecipientType +import javax.mail.internet.MimeMultipart import java.text.SimpleDateFormat @SuppressWarnings(['LineLength', 'GStringExpressionWithinString']) @Transactional(readOnly = true) class EmailService { - + def domainService + @Resource(name='welcomeEmailAttachments') + def welcomeEmailAttachments + static final String SERVICE_PROVIDER_WELCOME_EMAIL_TEMPLATE = -'Dear "$firstname $lastname",\n\nYour Price file access account has been successfully created. ' + -'Please contact Dealer Development if you have any questions regarding your account at (800)369-1000' + -'Your Price File password can be found below. Please wait a minimum of 30 minutes before trying to log into the service.' + -'\n\nAccount password is: ${password}' + -'\n\n** Please DO NOT reply to this notification. This is a notification only mailing. Replies to this message are not monitored or answered' + -'\n\nThank you\nLeMans Corporation Dealer Development' + 'Dear "$firstname $lastname",\n\nYour Price file access account has been successfully created. ' + + 'Please contact Dealer Development if you have any questions regarding your account at (800)369-1000' + + 'Your Price File password can be found below. Please wait a minimum of 30 minutes before trying to log into the service.' + + '\n\nAccount password is: ${password}' + + '\n\n** Please DO NOT reply to this notification. This is a notification only mailing. Replies to this message are not monitored or answered' + + '\n\nThank you\nLeMans Corporation Dealer Development' static final String SERVICE_PROVIDER_RESET_PASS_EMAIL_TEMPLATE = -'Dear "$firstname $lastname",\n\nYour Price file access account password has been reset.\n\nNew account password is: ${password}' + -'\n\n** Please DO NOT reply to this notification. This is a notification only mailing. Replies to this message are not monitored or answered' + -'\n\nThank you\nLeMans Corporation Dealer Development' + 'Dear "$firstname $lastname",\n\nYour Price file access account password has been reset.\n\nNew account password is: ${password}' + + '\n\n** Please DO NOT reply to this notification. This is a notification only mailing. Replies to this message are not monitored or answered' + + '\n\nThank you\nLeMans Corporation Dealer Development' static final String GENERIC_WELCOME_EMAIL_TEMPLATE = -'Dear "$firstname $lastname",\n\nYour user account has been successfully created. ' + -'Your password can be found below.' + -'\n\nAccount password is: ${password}' + 'Dear "$firstname $lastname",\n\nYour user account has been successfully created. ' + + 'Your password can be found below.' + + '\n\nAccount password is: ${password}' static final String GENERIC_RESET_PASS_EMAIL_TEMPLATE = -'Dear "$firstname $lastname",\n\nYour USER account password has been reset.\n\nNew account password is: ${password}' + 'Dear "$firstname $lastname",\n\nYour USER account password has been reset.\n\nNew account password is: ${password}' static final Map DEFAULT_DOMAIN_METADATA = [ - adminName: 'Support Adminstrator', - adminPhone: '608-758-7000', - setPasswordUrl: '', - resetPasswordUrl: '', - adminDisplayEmail: '' + adminName: 'Support Adminstrator', + adminPhone: '608-758-7000', + setPasswordUrl: '', + resetPasswordUrl: '', + adminDisplayEmail: '' ].asImmutable() - + static final String NO_REPLY_FROM = 'HelpDesk' def mailSender boolean validEmail(String emailAddress) { EmailValidator.instance.isValid(emailAddress) } - - void sendProviderWelcomeEmail(String firstName, String lastName, String newPass, String email) { + + void sendProviderWelcomeEmail(String firstName, String lastName, String newPass, String email) { Map binding = [firstname: firstName, lastname: lastName, password: newPass] MimeMessage mimeMessage = mailSender.createMimeMessage() MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true) @@ -60,7 +70,7 @@ helper.setTo(email) helper.setFrom('Dealer Development') mailSender.send(mimeMessage) - } + } void sendProviderPassResetEmail(String firstName, String lastName, String newPass, String email) { Map binding = [firstname: firstName, lastname: lastName, password: newPass] @@ -73,7 +83,7 @@ mailSender.send(mimeMessage) } - void sendWelcomeEmail(String firstName, String lastName, String newPass, String email) { + void sendWelcomeEmail(String firstName, String lastName, String newPass, String email) { Map binding = [firstname: firstName, lastname: lastName, password: newPass] MimeMessage mimeMessage = mailSender.createMimeMessage() MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true) @@ -82,7 +92,7 @@ helper.setTo(email) helper.setFrom('HelpDesk') mailSender.send(mimeMessage) - } + } void sendPassResetEmail(String firstName, String lastName, String newPass, String email) { Map binding = [firstname: firstName, lastname: lastName, password: newPass] @@ -97,72 +107,103 @@ /** * Sends a password changed email to the specified used. - * + * * @param user */ void passwordChanged(user, Integer domainId = null) { Map model = [subject: 'Password Changed', to: user.emailAddress, name: user.fullName] + metadata(domainId) MimeMessage msg = createHtmlEmailMessage('passwordChanged', model) mailSender.send(msg) } - + /** * Sends a reset password email to the specified used. - * + * * @param user */ void resetPassword(user, Integer domainId = null) { Map domainMetadata = metadata(domainId) Map model = [ - adminName: domainMetadata.adminName, adminPhone: domainMetadata.adminPhone, - adminDisplayEmail: domainMetadata.adminDisplayEmail, - subject: 'Reset Password', to: user.emailAddress, name: user.fullName, - expiry: formatExpiryDate(user.tokenExpiryDate), - setPasswordUrl: passwordUrl(user, domainMetadata.setPasswordUrl) + adminName: domainMetadata.adminName, adminPhone: domainMetadata.adminPhone, + adminDisplayEmail: domainMetadata.adminDisplayEmail, + subject: 'Reset Password', to: user.emailAddress, name: user.fullName, + expiry: formatExpiryDate(user.tokenExpiryDate), + setPasswordUrl: passwordUrl(user, domainMetadata.setPasswordUrl) ] MimeMessage msg = createHtmlEmailMessage('resetPassword', model) mailSender.send(msg) } - + /** * Sends a welcome email to the specified used. - * + * * @param user */ void welcome(user, Integer domainId = null) { Map domainMetadata = metadata(domainId) Map model = [ - adminName: domainMetadata.adminName, adminPhone: domainMetadata.adminPhone, - adminDisplayEmail: domainMetadata.adminDisplayEmail, websiteName: domainMetadata.websiteName, - subject: "Welcome to ${domainMetadata.websiteName}", to: user.emailAddress, name: user.fullName, - customWelcomeMsg: domainMetadata.customWelcomeMsg, expiry: formatExpiryDate(user.tokenExpiryDate), - setPasswordUrl: passwordUrl(user, domainMetadata.setPasswordUrl), dealerCode: user.dealerCode, - userName: user.userName, resetPasswordUrl: domainMetadata.resetPasswordUrl, websiteUrl: domainMetadata.websiteUrl + adminName: domainMetadata.adminName, adminPhone: domainMetadata.adminPhone, + adminDisplayEmail: domainMetadata.adminDisplayEmail, websiteName: domainMetadata.websiteName, + subject: "Welcome to ${domainMetadata.websiteName}", to: user.emailAddress, name: user.fullName, + customWelcomeMsg: domainMetadata.customWelcomeMsg, expiry: formatExpiryDate(user.tokenExpiryDate), + setPasswordUrl: passwordUrl(user, domainMetadata.setPasswordUrl), dealerCode: user.dealerCode, + userName: user.userName, resetPasswordUrl: domainMetadata.resetPasswordUrl, websiteUrl: domainMetadata.websiteUrl ] - MimeMessage msg = createHtmlEmailMessage('welcome', model) + MimeMessage msg = createHtmlEmailAttachmentMessage('welcome', model, domainId) mailSender.send(msg) } - + private String passwordUrl(user, String setPasswordUrl) { "$setPasswordUrl?dealerCode=$user.dealerCode&userName=$user.userName&token=$user.token" } - + private String formatExpiryDate(Date expiryDate) { new SimpleDateFormat("EEE, MMM dd 'at' hh:mm aa", Locale.US).format(expiryDate) } - + private Map metadata(Integer domainId) { domainService.findMetadata(domainId) ?: DEFAULT_DOMAIN_METADATA } - + private MimeMessage createHtmlEmailMessage(String viewName, Map model) { - String template = this.class.getResource('/emails/' + viewName + '.tmpl').text - String body = new SimpleTemplateEngine().createTemplate(template).make(model) + String body = getTemplateBody(viewName, model) + MimeMessage mimeMessage = message(model) + mimeMessage.setContent(body, 'text/html') + mimeMessage + } + + private MimeMessage createHtmlEmailAttachmentMessage(String viewName, Map model, Integer domainId) { + String body = getTemplateBody(viewName, model) + MimeMessage mimeMessage = message(model) + Multipart mp = new MimeMultipart('related') + MimeBodyPart mbp = new MimeBodyPart() + mbp.setText(body, 'UTF-8', 'html') + mp.addBodyPart(mbp) + File[] files = new File(welcomeEmailAttachments + File.separator + domainId).listFiles() + files.each { addAttachment(mp, it.path, it.name) } + mimeMessage.setContent(mp) + mimeMessage + } + + private MimeMessage message(Map model) { MimeMessage mimeMessage = mailSender.createMimeMessage() mimeMessage.setRecipient(RecipientType.TO, new InternetAddress(model.to)) mimeMessage.setFrom(new InternetAddress(NO_REPLY_FROM)) mimeMessage.setSubject(model.subject) - mimeMessage.setContent(body, 'text/html') mimeMessage } + + private String getTemplateBody(String viewName, Map model) { + String template = this.class.getResource('/emails/' + viewName + '.tmpl').text + String body = new SimpleTemplateEngine().createTemplate(template).make(model) + body + } + + private void addAttachment(Multipart multipart, String filePath, String file) { + FileDataSource source = new FileDataSource(filePath) + BodyPart bodyPart = new MimeBodyPart() + bodyPart.setDataHandler(new DataHandler(source)) + bodyPart.setFileName(file) + multipart.addBodyPart(bodyPart) + } } Index: trunk/grails-app/conf/spring/resources.groovy =================================================================== diff -u -r8568 -r8936 --- trunk/grails-app/conf/spring/resources.groovy (.../resources.groovy) (revision 8568) +++ trunk/grails-app/conf/spring/resources.groovy (.../resources.groovy) (revision 8936) @@ -8,11 +8,15 @@ Environment current = Environment.current if (current != Environment.PRODUCTION) { emailHost(String, 'localhost') + welcomeEmailAttachments(String, 'src/test') } else { emailHost(org.springframework.jndi.JndiObjectFactoryBean) { jndiName = 'java:comp/env/emailHost' } + welcomeEmailAttachments(org.springframework.jndi.JndiObjectFactoryBean) { + jndiName = 'java:comp/env/welcomeEmailAttachments' + } } mailSender(JavaMailSenderImpl) {