Actually thr rmlan solution works with the following fix. Since the onConfigChange compares hashCode of existing config map and new one, so if you set new configs in original configuration (Holders.config.grails.mail), then both configs are same and it never pass the condition to apply new changes, so a new structure should be created and pass it to notifyOfEvent method to mark the change as different hashCodes.
def mailConfig = [ grails: [ mail: [:] ] ]
mailConfig.grails.mail.host = newHost
mailConfig.grails.mail.port = newPort
Holders.pluginManager.getGrailsPlugin('mail').
notifyOfEvent(GrailsPlugin.EVENT_ON_CONFIG_CHANGE, mailConfig)
Still using async-mail and this one make the below exception
No qualifying bean of type [grails.plugin.mail.MailService] is defined: expected single matching bean but found 2: nonAsynchronousMailService,mailService
that is thrown because of the following part of onConfigChange
event.ctx.getBean(MailService.class).setPoolSize(mailConfig.poolSize?:null)
Commenting it let it works as a workaround, but making sendMail of mail plugin is called, not async-mail, so exception may raise if async-mail features is used on constructing mail. Hence to use async-mail in this workaround should use sendAsynchronousMail method.