Codersee

How to Send Emails with Spring Boot and Kotlin

A featured image for category: Spring

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
}

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:
Photo contains the screenshot showing allow less secure apps page in gmail settings
We might also receive the email asking us to confirm this action:
Photo contains the screenshot showing email with confirmation request from Gmail

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.

2 Responses

Leave a Reply

Your email address will not be published.

Categories

Author

Piotr Wolak

Piotr Wolak

Founder Of Codersee

Join Newsletter And Get 2 FREE EBOOKS

Image shows the covers of free ebooks accessible for newsletter subscribers.

Join the FREE weekly newsletter and get two free eBooks:

Image shows the covers of free ebooks accessible for newsletter subscribers.

You may opt out any time. Terms of Use and Privacy Policy.

To make Codersee work, we log user data. By using our site, you agree to our Privacy Policy and Terms of Use.