Grails2.1 Dynamic mail configuration - grails

I am trying to send an email from a grails app. I tried with recommended settings using gmail and it worked fine. I sent mail successfully. But I want to override the username and password dynamically. I don't know how can I do it. Can anybody help?
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "faruq#gmail.com" // Want to change dynamically like variable ${branch.mail}
password = "12345" // Want to change dynamically like variable ${branch.pass}
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
I use this process for overriding the username from the controller
grailsApplication.config.grails.mail.username = Branch.get(2).mail
by this process username successfully changes
here Branch is my domain class and mail is property
but an authentication problem comes up:
javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted
Now what can I do?

You can use an external configuration file - put placeholder values in the main Config.groovy
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "<changeme>"
password = "<changeme>"
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
and then override them with the correct values in the external config:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
To be able to change the credentials dynamically at run time it gets rather more complicated. Under the covers the mail plugin creates a Spring bean which is an instance of JavaMailSenderImpl to handle the actual sending of emails, and this bean is configured by default with static settings from the config. But at runtime this class appears to call its own getUsername() and getPassword() every time it needs to send a message. So you could replace this bean with your own custom subclass of JavaMailSenderImpl that overrides these methods to pull the details from the request context (code example, not tested, and imports/error handling omitted):
src/groovy/com/example/RequestCredentialsMailSender.groovy
class RequestCredentialsMailSender extends JavaMailSenderImpl {
public String getUsername() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailUsername ?: super.getUsername()
}
public String getPassword() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailPassword ?: super.getPassword()
}
}
You'd have to register this bean in your resources.groovy, and duplicate a fair bit of the configuration from the mail plugin itself, which is less than ideal:
grails-app/conf/spring/resources.groovy
beans = {
mailSender(com.example.RequestCredentialsMailSender) {
def mailConf = application.config.grails.mail
host = mailConf.host
port = mailConf.port
username = mailConf.username // the default, if not set in request
password = mailConf.password
protocol = mailConf.protocol
javaMailProperties = mailConf.props
}
}
Now when you need to send mail from a controller you can do
request.mailUsername = Branch.get(2).mail
request.mailPassword = Branch.get(2).mailPassword
sendMail { ... }

Just wanted to verify Ian's answer and expand it.
In the default Config.groovy file I have the added external config line:
grails.config.locations = [
"file:./${appName}-config.groovy",
"classpath:${appName}-config.groovy"
]
....
// and here is the mail config as above
grails{
mail{
....
In the config file at the root level I have my config file: TestApp-config.groovy (where TestApp is the name of my app) as above:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
Didn't need anything past this and it worked great.

We can also use replyTo field if our aim is only to get the reply back on specific Email Id. We can dynamically pass an email id to "replyTo" field and can expect an email back on the same.
Example :
asynchronousMailService.sendMail
{
to ["xyz#gmail.com","pqr#gmail.com"]
subject "Subject Text"
if(ccs) cc ["xyz1#gmail.com","pqr1#gmail.com"]
if(bccs) bcc ["xyz2#gmail.com","pqr2#gmail.com"]
if(replyTo) replyTo "xyz#gmail.com"
if(attachBytes) attachBytes attachBytes
}
NOTE: Adding "replyTo" will only allow us to get the emails back on the specified email-id and will not send the email from the configured email.
It was suitable in my use case. Hope it helps !

Related

Can't pass password from credentialsJSON to commitStatusPublisher (bitbucket server) Teamcity

It seems that i have an old version of commitStatusPublisher plugin and it can't convert credentialsJSON string to its value. In any other situation I can access password with
params.findRawParam("env.mypass")!!.value
or in buildstep, script content
$mypass
But commitStatusPublisher not working with it.
Code example
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.commitStatusPublisher
params {
password("env.mypass", "credentialsJSON:8420d5dc-1d32-4f9e-a74d-c9444be05c23", display = ParameterDisplay.HIDDEN)
}
features {
commitStatusPublisher {
publisher = bitbucketServer {
url = "https://bitbucket.domain.com/"
userName = "user"
password = params.findRawParam("env.mypass")!!.value
}
}
}
Maybe I can somehow extract 'raw' var to use it for that plugin?
for example
var pass = something("env.mypass")
features {
commitStatusPublisher {
publisher = bitbucketServer {
url = "https://bitbucket.domain.com/"
userName = "user"
password = pass
}
}
}
In the result i want to keep password in TC tokens and use it with my version of commitStatusPublisher
Seems like a bug.
Recreating the token resolves problem

How to provide credentials to Fetch() and Pul() methods?

I'm looking for a nice clean example of how to do a pull using lidgit2sharp. I took the example here which does a fetch, but the reference to Credentials is throwing an exception.
using (var repo = new Repository(workingDir, null))
{
Remote remote = repo.Network.Remotes.Add("master", repoUrl);
repo.Network.Fetch(remote,
{
Credentials credentials = new Credentials
{
Username = "username",
Password = "password"
}
});
}
The exception is Cannot create an instance of the abstract class or
interface 'LibGit2Sharp.Credentials'
It's telling you in the error: Credentials is an abstract class, interface, whatever.
Try this:
Credentials credentials = new UsernamePasswordCredentials()
{
Username = "username",
Password = "password"
}

AWS SES, Mail plugin and Grails configuration

I'm trying to set up the Mail plugin with my SES credentials, but I am obviously missing something because I keep getting this error:
Class: javax.mail.NoSuchProviderException
Message: No provider for aws
I've added the following to my Config.groovy:
grails {
mail {
host = "email-smtp.us-east-1.amazonaws.com"
port = 465
username = "XXXXXXXXX"
password = "YYYYYYYYY"
props = [
'mail.transport.protocol': 'aws',
'mail.aws.class': 'com.amazonaws.services.simpleemail.AWSJavaMailTransport',
'mail.aws.user': 'WWWWWWWWWWWW',
'mail.aws.password': 'ZZZZZZZZZZZ'
]
}
}
I've been looking through all the possible tutorials, half of them were from the time SES didn't support SMTP, thats why I have the class reference from the maven repo.
Does anyone know how I can configure this?
This is what I have been using successfully -
grails {
mail {
host = "email-smtp.us-east-1.amazonaws.com"
port = 587
username = "smtp user name"
password = "smtp password"
props = ["mail.smtp.starttls.enable":"true",
"mail.smtp.port":"587"]
}
}
Let me know if the above works

How to send mail from a Domain/Service in Grails

I have this plugin installed, I want to send mails from a Service/Domain class method , I was doing like this
class TrainingService {
def mailService
public def sendMail() {
mailService.sendMail {
multipart true
to "abc#xyz.com"
subject "Hello,"
body 'How are you?'
}
}
I got error "Cannot invoke method sendMail() on null object", How to resolve this
I am missing the "from" attribute and if you're using multipart email, you should also fill in additional parts of the email, snippet from my code:
mailService.sendMail {
multipart true
from '"Some account" <someaccount#email.com>'
to 'anotheremail#somedomain.com'
bcc emailAddresses.toArray()
subject dto.title
body emailPart1
html g.render(
template: 'emailNotification',
model: [ name: dto.name ]
)
}
Have you configured your SMTP server. You need these entries in your config file for mail to work. Do you have these ?
grails {
mail {
host = "hostname"
pop_port = 25
username = "username"
password = "password"
type = "pop3"
}
}
you can find more information about the configuration here
I got this error when I was passing variables called 'from' and 'to' into the method that was using sendMail. Try renaming the sendMail method and making sure that you don't have any conflicting variable names.

how to integration test email body in a Grails Service that uses the Mail plugin

I am attempting to write integration tests for a Grails service that does, among other things, send email via the excellent Mail Plugin. I can disable the actual sending of email via configuration, which is great, but I would like to verify that the parameters are correct body is being rendered correctly, or at very least that the method has been called when I expect. As per the documentation, the full path to GSP for the body must be supplied.
As part my test I'd like to do something like this - is there a way to access the email body and other parameters programmatically after sending?
sendMail {
to myemailparams.to
subject myemailparams.subject
body( view:"/emailviews/someemailview",
model:[contentparam: myemailparams.somecontentvalue)
}
//verify correct sending to and subject parameters, and that body contains correct contentvalue
//or at least that the method has been called (Mock it out?)
Note I realize that I can encapsulate the testing of the email body rendering into a separate isolated test that doesn't involve the mail plugin. But the purpose of this integration test is to ensure a lot of things, including the email send, happen correctly upon call to the service method. I would even be satisfied with an answer that describes how to mock the service, and a check that verifies 'sendMail' has been called when expected.
You can override the sendMail method using metaClass and then do some checking to ensure that sendMail was called:
void testSendMail() {
MyClass myClass = new MyClass()
def sendMailCalled = false
myClass.metaClass.sendMail = { Closure c->
sendMailCalled = true
}
myClass.functionThatCallsSendMail()
assert sendMailCalled
}
Here is an example of how I assert things that were sent to MailService:
def setup(){
mailParams = [:]
mockMailService.ignore.sendMail{ callable ->
messageBuilder = new MailMessageBuilder(null, new ConfigObject())
messageBuilder.metaClass.body = { Map params ->
mailParams.body = params
}
messageBuilder.metaClass.async = { Boolean param ->
mailParams.async = param
}
messageBuilder.metaClass.to = { String param ->
mailParams.to = param
}
messageBuilder.metaClass.subject = { String param ->
mailParams.subject = param
}
callable.delegate = messageBuilder
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.call()
}
service.mailService = mockMailService.proxyInstance()
}
Then, In my test, after executing the method that sends mail, I assert this way (Spock syntax for assertions):
then:
mailParams.to == 'test#test.com'
mailParams.async == true
mailParams.subject == 'fnuser.billingEmail.subject{}en'
mailParams.body.view == '/mailtemplates/setBillingEmail'
mailParams.body.model.destinationUrl == "myDestinationUrl"
mailParams.body.model.logoUrl == 'myUrl/templatelogo.png'
mailParams.body.model.locale == Locale.ENGLISH

Resources