1. Introduction
Hello dear reader ?. I’m pleased to welcome you to our sixth article. I am so happy and excited that our community is growing at this rate and that I can share my knowledge with you.
In this tutorial, we will learn how to send emails using JavaMailSender in Spring Boot Kotlin application. This example is a step by step guide for sending email via Gmail SMTP server (but it might be also adapted for other providers pretty easily).
2. Imports
Let’s start with adding the required dependencies to our existing Spring Boot project:
implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-web")
Thanks to spring-boot-starter-mail, we will be able to send emails using Java Mail and Spring Framework’s JavaMailSender.
3. Configure JavaMailSender
As the next step, let’s configure JavaMailSender. There are basically two ways we can do this- using the application properties file, as well as manually defining the @Bean of JavaMailSender type.
3.1. Configure JavaMailSender Using Configuration File
Let’s start with the easier way (at least in my opinion) and add the following configuration to our application.yaml file:
spring: mail: host: ${MAIL_SENDER_HOST} port: ${MAIL_SENDER_PORT} username: ${MAIL_SENDER_USERNAME} password: ${MAIL_SENDER_PASSWORD} properties: mail: transport: protocol: ${MAIL_SENDER_PROTOCOL} debug: ${MAIL_SENDER_DEBUG} smtp: auth: ${MAIL_SENDER_AUTH} starttls: enable: ${MAIL_SENDER_STARTTLS_ENABLE}
Please notice, that all of the above configurations have to be set using environment variables. To set up our project with the Gmail SMTP server, we will need to use the following values:
- MAIL_SENDER_HOST– smtp.gmail.com
- MAIL_SENDER_PORT– 587
- MAIL_SENDER_USERNAME– our Gmail email
- MAIL_SENDER_PASSWORD– our password
- MAIL_SENDER_PROTOCOL– smtp
- MAIL_SENDER_DEBUG – true
- MAIL_SENDER_AUTH– true
- MAIL_SENDER_STARTTLS_ENABLE– true
3.2. Configure JavaMailSender @Bean Definition
Sometimes, we would like to define the configuration bean manually. Let’s start with implementing MailSenderProperties class, which will bind and validate properties from application.yaml file:
@ConstructorBinding @ConfigurationProperties(prefix = "mail-sender") class MailSenderProperties( val host: String, val port: Int, val username: String, val password: String, val protocol: String, val auth: Boolean, val starttlsEnable: Boolean, val debug: Boolean )
The @ConstructorBinding annotation will bind the external properties to the constructor parameters.
As the next step, let’s edit the application.yaml file:
mail-sender: host: ${MAIL_SENDER_HOST} port: ${MAIL_SENDER_PORT} username: ${MAIL_SENDER_USERNAME} password: ${MAIL_SENDER_PASSWORD} protocol: ${MAIL_SENDER_PROTOCOL} auth: ${MAIL_SENDER_AUTH} starttls-enable: ${MAIL_SENDER_STARTTLS_ENABLE} debug: ${MAIL_SENDER_DEBUG}
Please notice, that the prefix of the properties has to match the prefix set inside @ConfigurationProperties annotation.
After that, let’s create the MailSenderConfig class and annotate it with @EnableConfigurationProperties:
@Configuration @EnableConfigurationProperties(MailSenderProperties::class) class MailSenderConfig( private val mailSenderProperties: MailSenderProperties )
The @EnableConfigurationProperties annotation enables support for @ConfigurationProperties annotated beans.
With that being done, we can finally define JavaMailSender bean:
@Bean fun javaMailSender(): JavaMailSender { val mailSender = JavaMailSenderImpl() mailSender.host = mailSenderProperties.host mailSender.port = mailSenderProperties.port mailSender.username = mailSenderProperties.username mailSender.password = mailSenderProperties.password configureJavaMailProperties(mailSender.javaMailProperties) return mailSender } private fun configureJavaMailProperties(properties: Properties) { properties["mail.transport.protocol"] = mailSenderProperties.protocol properties["mail.smtp.auth"] = mailSenderProperties.auth properties["mail.smtp.starttls.enable"] = mailSenderProperties.starttlsEnable properties["mail.debug"] = mailSenderProperties.debug }
Make a real progress thanks to practical examples, exercises, and quizzes.
- 64 written lessons
- 62 quizzes with a total of 269 questions
- Dedicated Facebook Support Group
- 30-DAYS Refund Guarantee
4. Allow Less Secure Apps In Gmail Settings
But before we will send our first email, we have to make sure, that we won’t be blocked by our SMTP server. To do that in Gmail, please follow this link and turn the access on:
We might also receive the email asking us to confirm this action:
5. Send Emails
5.1. Send Simple Email
Let’s start simply by creating the EmailSenderService containing one function:
@Service class EmailSenderService( private val emailSender: JavaMailSender ) { fun sendEmail( subject: String, text: String, targetEmail: String ) { val message = SimpleMailMessage() message.setSubject(subject) message.setText(text) message.setTo(targetEmail) emailSender.send(message) } }
This uncomplicated function takes the subject, text, and the target email as the parameters and sends the given simple mail message using injected JavaMailSender instance.
5.2. Send Email Using Template
Sometimes, we would like to prepare one reusable template and personalize it depending on our needs. Let’s create a TemplateConfig class and define the template bean:
@Configuration class TemplateConfig { @Bean fun exampleNewsletterTemplate(): SimpleMailMessage { val template = SimpleMailMessage() template.setSubject("Newsletter") template.setText(""" Hello %s, This is an example newsletter message """.trimIndent() ) return template } }
To make our template eligible for personalization, we’ve used Java String formatting specifier- %s, which will allow us to pass the name of the user.
As the next step, let’s inject the template to the previously created service:
@Service class EmailSenderService( private val emailSender: JavaMailSender, private val template: SimpleMailMessage )
And finally, let’s create the sendEmailUsingTemplate function, which will take the user email and name as the parameter:
fun sendEmailUsingTemplate( name: String, targetEmail: String ) { val message = SimpleMailMessage(template) val text = template.text message.setText(text!!.format(name)) message.setTo(targetEmail) emailSender.send(message) }
5.2. Send Email With Attachment
Now, let’s learn how to send the email containing an attachment. Let’s create a file named file.txt and let’s place it inside the resources directory of the project. Then, let’s inject the file inside our service:
class EmailSenderService( private val emailSender: JavaMailSender, private val template: SimpleMailMessage, @Value("classpath:file.txt") private val resourceFile: Resource )
As the last step, let’s implement the function, which will take the target email as the argument:
fun sendEmailWithAttachment( targetEmail: String ) { val message: MimeMessage = emailSender.createMimeMessage() val helper = MimeMessageHelper(message, true) helper.setTo(targetEmail) helper.setSubject("Email with attachment") helper.setText("Please see the file in attachment") helper.addAttachment("file.txt", resourceFile) emailSender.send(message) }
5. Create a Test Controller
Finally, we can create the example controller and prepare some endpoints for testing purposes:
@RestController class TestController( private val emailSenderService: EmailSenderService ) { @PostMapping("/api/email") fun sendSimpleEmail( @RequestBody request: EmailRequest ): ResponseEntity { emailSenderService.sendEmail( subject = request.subject!!, targetEmail = request.targetEmail!!, text = request.text!! ) return ResponseEntity.noContent().build() } @PostMapping("/api/email/template") fun sendSimpleTemplateEmail( @RequestBody request: EmailRequest ): ResponseEntity { emailSenderService.sendEmailUsingTemplate( name = request.name!!, targetEmail = request.targetEmail!! ) return ResponseEntity.noContent().build() } @PostMapping("/api/email/attachment") fun sendEmailWithAttachment( @RequestBody request: EmailRequest ): ResponseEntity { emailSenderService.sendEmailWithAttachment( targetEmail = request.targetEmail!! ) return ResponseEntity.noContent().build() } }
Also, please remember to implement EmailRequest class used in the above functions:
class EmailRequest( val subject: String?, val targetEmail: String?, val text: String?, val name: String? )
5. Testing with Curl
And finally, we can run our application and check if everything works fine using the curl command:
curl -H "Content-Type: application/json" \ -d '{"subject":"Example subject", "targetEmail":"your@mail.com", "text":"Example content."}' \ http://localhost:8080/api/email
curl -H "Content-Type: application/json" \ -d '{"name":"Piotr","targetEmail":"your@mail.com"}' \ http://localhost:8080/api/email/template
curl -H "Content-Type: application/json" \ -d '{"targetEmail":"your@mail.com"}' \ http://localhost:8080/api/email/attachment
Please remember to change the targetEmail in the requests to the valid one. If everything has been set up correctly, then we should receive three emails to our inbox.
6. Summary
In this step by step tutorial, we’ve learned how to send emails using JavaMailSender in a Spring Boot Kotlin application. I hope that you’ve enjoyed it and I will be more than happy if you would like to share some feedback with me (you can do that using our page, group, or contact form). I really appreciate each suggestion that I get from you.
For the source code of the project, please visit our project on GitHub.
5 Responses
Perfect example!!..working perfectly. Well explained
Thank You so much for Your kind words ! ๐
Great Example. Thanks
fyi, the constructor binding on properties class is deprecated on spring-version 3.0.0 above.
they said changed the annotation level to “type-level”. there are links you can read below, if you want to know details about it.
https://stackoverflow.com/questions/73096757/what-is-type-level-annotation?noredirect=1&lq=1
https://stackoverflow.com/questions/73096757/what-is-type-level-annotation?noredirect=1&lq=1
Hi Jeff!
Yes, you’re totally right, and thank you for your comment. At some point in the future, I’ll update dependencies to be up-to-date.
It’s almost impossible to track all articles (60+) and deliver new content at the same time.
Of course, if you’d like to, you can always create a PR https://github.com/codersee-blog/kotlin-spring-boot-mail-sender/pulls
Thank you!