Omar Faruq
Omar Faruq

Reputation: 1220

Grails2.1 Dynamic mail configuration

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 = "[email protected]"    // 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?

Upvotes: 1

Views: 1781

Answers (3)

Vaibhav Sharma
Vaibhav Sharma

Reputation: 129

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 ["[email protected]","[email protected]"] subject "Subject Text" if(ccs) cc ["[email protected]","[email protected]"] if(bccs) bcc ["[email protected]","[email protected]"] if(replyTo) replyTo "[email protected]" 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 !

Upvotes: 0

Nathan Dunn
Nathan Dunn

Reputation: 447

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 = "[email protected]"
    password = "12345"
  }
}

Didn't need anything past this and it worked great.

Upvotes: 0

Ian Roberts
Ian Roberts

Reputation: 122394

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 = "[email protected]"
    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 { ... }

Upvotes: 1

Related Questions