<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Email Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/email/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Email Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</title>
		<link>https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/</link>
					<comments>https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Thu, 02 Feb 2023 10:58:21 +0000</pubDate>
				<category><![CDATA[Ktor]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MailerSend]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5504278</guid>

					<description><![CDATA[<p>In this, hands-on tutorial I will show you how to send transactional emails using Ktor, Kotlin, and MailerSend.</p>
<p>The post <a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/">Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Hello and welcome to my next, hands-on tutorial 🙂 This time, I would like to show you <strong>how to send transactional emails using Ktor, Kotlin, and MailerSend</strong>.</p>
<p>Sooner or later, every developer will have to implement email-sending functionality in their application and it&#8217;s worth checking out various solutions, to pick the one that will best meet our needs.</p>
<p>And although the term &#8220;transactional emails&#8221; sounds complicated, in this tutorial I will prove how easily we can use them with Ktor and Kotlin.</p>
<h2>Video Tutorial</h2>
<p>If you prefer <strong>video content</strong>, then check out my video:</p>
<div style="text-align: center; width: 80%; margin-left: 10%;">
<a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F29xM0SpzEEg%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>
</div>
<p>&nbsp;</p>
<p>If you find this content useful,<strong> please leave a subscription </strong> 😉</p>
<h2>Prerequisites</h2>
<p>Before we start, let&#8217;s see what exactly we will need for this tutorial.</p>
<p>First of all, we will need a <a href="https://www.mailersend.com?ref=fmebcn1eb2vc" target="_blank" rel="noopener">MailerSend account</a>. The free version will be fair enough for the purpose of learning and even simple projects.</p>
<blockquote><p>Note: the above link is a referral and if you will purchase any paid plan, I&#8217;ll get a small commission for that. To be clear: this fact affects the merits of this article in no way 🙂</p></blockquote>
<p>Additionally, <strong>you will need to have a domain, which you can verify</strong>. This is necessary, in order to work with any transactional email providers.</p>
<h2>Configure Domain in MailerSend</h2>
<p>I won&#8217;t go into much detail in this paragraph, because DNS settings will be dependent on your domain registrar. Nevertheless, let&#8217;s take look at how to add a new domain to MailerSend.</p>
<p>So, assuming we created our account and verified the email along with their policies, we should see the following:</p>
<p>&nbsp;</p>
<p><img fetchpriority="high" decoding="async" class="size-full wp-image-5504282 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1.png" alt="Screenshot presents MailerSend dashboard." width="1427" height="738" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1.png 1427w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-300x155.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-1024x530.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-768x397.png 768w" sizes="(max-width: 1427px) 100vw, 1427px" /></p>
<p>&nbsp;</p>
<p>As the next step, let&#8217;s click the <strong>Start</strong> button next to the <em>&#8220;Add a sending domain&#8221;</em>:</p>
<p>&nbsp;</p>
<p><img decoding="async" class="alignnone size-full wp-image-5504283" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2.png" alt="Screenshot presents a modal, which allows user to enter a domain name, which we would like to register for transactional emails sending." width="1291" height="618" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2.png 1291w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-300x144.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-1024x490.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-768x368.png 768w" sizes="(max-width: 1291px) 100vw, 1291px" /></p>
<p>&nbsp;</p>
<p>Right here, let&#8217;s specify the domain name- <em>test.codersee.com</em> in my case- and confirm with the <strong>Add domain</strong> button.</p>
<p>Nextly, we should see the Domain verification modal:</p>
<p>&nbsp;</p>
<p><img decoding="async" class="size-full wp-image-5504284 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3.png" alt="Screenshot presents domain verification modal with SPF, DKIM and RETURN-PATH settings to copy" width="891" height="1095" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3.png 891w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-244x300.png 244w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-833x1024.png 833w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-768x944.png 768w" sizes="(max-width: 891px) 100vw, 891px" /></p>
<p>&nbsp;</p>
<p>As we can see, in order to verify our domain, we need to navigate to our domain registrar and modify the DNS settings using the values specified in the modal. When it&#8217;s done, let&#8217;s click the <strong>Check/Re-check</strong> now button.</p>
<blockquote><p>Note: DNS propagation can take some time, so don&#8217;t worry if you see the error messages (just like above). In such a case, give it some time and please get back to this page. MailerSend will send you an e-mail when everything is verified, as well.</p></blockquote>
<p>If everything succeeded, we should see the following page:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504285 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4.png" alt="" width="1410" height="706" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4.png 1410w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-300x150.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-1024x513.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-768x385.png 768w" sizes="auto, (max-width: 1410px) 100vw, 1410px" /></p>
<p>&nbsp;</p>
<p>One <strong>important note</strong> before we head to the next part. At this point, we <strong>will be able to send emails only to addresses and domains we previously verified</strong>&#8211; the e-mail address we use for registration and all addresses in a verified domain in our case.</p>
<p>Nevertheless, <strong>if you would like to send emails outside the domain, you will need to get approval</strong>.</p>
<h2>Generate API Key</h2>
<p>In order to send transactional emails with MailerSend in our Ktor app, we will need to generate a new <strong>API key</strong>.</p>
<p>To do so, let&#8217;s navigate to our domains (Email -&gt; Domains in the left sidebar) and click the manage button:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504288 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5.png" alt="Screenshot presents the test.codersee.com domain details page." width="1397" height="766" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5.png 1397w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-300x164.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-1024x561.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-768x421.png 768w" sizes="auto, (max-width: 1397px) 100vw, 1397px" /></p>
<p>&nbsp;</p>
<p>On this page, we can manage API tokens and configure plenty of other things, like webhooks or tracking.</p>
<p>Anyway, let&#8217;s click the Generate new token button:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504289 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6.png" alt="Screenshot presents a MailerSend modal, where we can set a name for the API token and permission level for it." width="618" height="581" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6.png 618w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6-300x282.png 300w" sizes="auto, (max-width: 618px) 100vw, 618px" /></p>
<p>&nbsp;</p>
<p>As we can see, right here we can specify the name and access granted to the new token. And although for simplicity we will stick with &#8220;Full access&#8221;, in real-life scenarios we should always follow the principle of least privilege.</p>
<p>Finally, let&#8217;s click the Create token:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504290 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7.png" alt="Screenshot shows a modal with a censored API token value " width="637" height="537" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7.png 637w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7-300x253.png 300w" sizes="auto, (max-width: 637px) 100vw, 637px" /></p>
<p>&nbsp;</p>
<p>As can be seen, the API token was created successfully and it&#8217;s time to save the value.</p>
<blockquote><p>Note: please persist this value securely and never share it with anyone!</p></blockquote>
<h2>Generate Ktor Project</h2>
<p>With all of that being done in MailerSend, we can finally switch to the Ktor &amp; Kotlin part of our tutorial about transactional emails.</p>
<p>As always, let&#8217;s navigate to <a href="https://start.ktor.io/" target="_blank" rel="noopener">https://start.ktor.io/</a> and specify desired project settings:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504291 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8.png" alt="The image shows Ktor Project Generator page, which we use to generate app skeleton, which then will be used to implement transactional emails with MailerSend." width="702" height="852" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8.png 702w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8-247x300.png 247w" sizes="auto, (max-width: 702px) 100vw, 702px" /></p>
<p>Following, let&#8217;s click the Add plugins (we don&#8217;t need anything else), generate the project, and import it to our IDE.</p>
<p>Nextly, let&#8217;s add the <strong>Ktor client</strong> and <strong>Jackson</strong> dependencies inside the build.gradle.kts:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">implementation("io.ktor:ktor-client-core-jvm:$ktor_version")
implementation("io.ktor:ktor-client-okhttp:$ktor_version")

implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-jackson:$ktor_version")
</pre>
<p>Of course, Jackson is not the only option here, and GSON, or kotlinx.serialization are well supported in Ktor, as well.</p>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img loading="lazy" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<h2>Configure Client</h2>
<p>As the next step, let&#8217;s navigate to the<em> application.conf</em> file and add a custom MailerSend config:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">mailersend {
  token = ${MAILERSEND_TOKEN}
  baseUrl = ${MAILERSEND_BASE_URL}
}
</pre>
<p>This way, we can pass the token and URL values securely through environment variables. And although the token will be unique, for the baseUrl, let&#8217;s set <strong>https://api.mailersend.com/v1/</strong>.</p>
<p>Nextly, let&#8217;s create the <strong>MailerSendClient.kt</strong> file and put the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun Application.configureClient() {

  val token = environment.config.property("mailersend.token").getString()
  val baseUrl = environment.config.property("mailersend.baseUrl").getString()

  val mailerSendClient = HttpClient {
    install(ContentNegotiation) {
      jackson()
    }
  }

  runBlocking {
    // To be done in the next paragraphs
  }
}
</pre>
<p>As we can see, the above function reads configuration properties and installs the <span style="white-space: pre-wrap;"><em>ContentNegotiation</em> plugin using <em>Jackson</em>. Moreover, we&#8217;ve prepared the <em>runBlocking</em> block, where we will invoke our future functions. </span></p>
<p>Lastly, let&#8217;s navigate to the <em>Application.kt</em> file and make use of our config:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun Application.module() {
  configureClient()
}
</pre>
<p>At this point, we can run our application and verify that it is working, as expected. If we forget to set environment variables correctly, we should see something like this:</p>
<blockquote><p>Exception in thread &#8220;main&#8221; com.typesafe.config.ConfigException $ UnresolvedSubstitution: application.conf @ [&#8230;] Could not resolve substitution to a value: ${MAILERSEND_BASE_URL}</p></blockquote>
<h2>Send Simple Email</h2>
<p>With all of that done, we can finally start sending transactional emails. In this paragraph, we will learn how to send a simple email with MailerSend.</p>
<h3>Implement EmailRequest</h3>
<p>As the first step, let&#8217;s create a new data class called <strong>EmailRequest</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@JsonInclude(JsonInclude.Include.NON_NULL)
data class EmailRequest(
    val from: Recipient,
    val to: List&lt;Recipient&gt;,
    val subject: String,
    val text: String,
    val html: String,
    val variables: List&lt;Variable&gt;? = null
) {
    data class Recipient(
        val email: String,
        val name: String
    )

    data class Variable(
        val email: String,
        val substitutions: List&lt;Substitution&gt;
    ) {
        data class Substitution(
            @JsonProperty("var") val variable: String,
            val value: String
        )
    }
}
</pre>
<p>Basically, objects of this class will be serialized into JSONs when querying MailerSend API.</p>
<p>The <strong>@JsonInclude</strong> annotation states that if the value is set to null, then it should not be added to the JSON payload (so we won&#8217;t send <code class="EnlighterJSRAW" data-enlighter-language="raw">"whatever": null</code>) . Additionally, MailerSend requires us to send the &#8220;var&#8221; field inside the substitution. Nevertheless, <strong>var</strong> is a reserved keyword in Kotlin, so we have to make use of the <strong>@JsonProperty</strong>.</p>
<h3>Use Ktor Client to Perform Requests</h3>
<p>Following, let&#8217;s add a new function called <em>sendSingleEmail</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendSingleEmail(
  mailerSendClient: HttpClient,
  url: String,
  token: String,
  emailRequest: EmailRequest
): HttpResponse =
    mailerSendClient.post(url) {
      headers {
        append(HttpHeaders.Authorization, "Bearer $token")
      }
      contentType(ContentType.Application.Json)
      setBody(emailRequest)
    }
</pre>
<p>As we can see, this one is responsible for <strong>sending POST requests to the passed URL </strong>with the <strong>Authorization header</strong> containing the <strong>Bearer token</strong>.</p>
<p>Moreover, the function takes the EmailRequest as an argument, which makes it reusable.</p>
<h3>Send Transactional Client with Ktor Client</h3>
<p>Lastly, let&#8217;s implement the <em>sendSimpleMessage</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendSimpleMessage(
    mailerSendClient: HttpClient,
    baseUrl: String,
    token: String
) {
    val subject = "Hello from {\$company}!"
    val html = """
        Hello &lt;b&gt;{${'$'}name}&lt;/b&gt;, nice to meet you!
    """.trimIndent()
    val text = """
        Hello {${'$'}name}, nice to meet you!
    """.trimIndent()

    val emailRequest = EmailRequest(
        from = EmailRequest.Recipient(
            email = "example@test.codersee.com",
            name = "Codersee"
        ),
        to = listOf(
            EmailRequest.Recipient(
                email = "example@test.codersee.com",
                name = "Pjoter"
            )
        ),
        subject = subject,
        html = html,
        text = text,
        variables = listOf(
            EmailRequest.Variable(
                email = "example@test.codersee.com",
                substitutions = listOf(
                    EmailRequest.Variable.Substitution(
                        variable = "company",
                        value = "Codersee"
                    ),
                    EmailRequest.Variable.Substitution(
                        variable = "name",
                        value = "Piotr"
                    )
                )
            )
        )
    )

    val response = sendSingleEmail(
        mailerSendClient = mailerSendClient,
        url = "$baseUrl/email",
        token = token,
        emailRequest = emailRequest
    )

    if (response.status == HttpStatusCode.Accepted)
        println("Email sent successfully.")
    else
        println("Error when sending email.")
}
</pre>
<p>And although the above code snippet consists of a lot of lines, it&#8217;s definitely easier than it looks.</p>
<p>Firstly, we prepare the EmailRequest instance, which after serialization, will become this JSON:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">{
    "from": {
        "email": "example@test.codersee.com",
        "name": "Codersee"
    },
    "to": [
        {
            "email": "example@test.codersee.com",
            "name": "Pjoter"
        }
    ],
    "subject": "Hello from {$company}!",
    "html": "Hello &lt;b&gt;{$name}&lt;/b&gt;, nice to meet you!"
    "variables": [
        {
            "email": "example@test.codersee.com",
            "substitutions": [
                {
                    "var": "company",
                    "value": "Codersee"
                },
                {
                    "var": "name",
                    "value": "Piotr"
                }
            ]
        }
    ]
}
</pre>
<p>Whereas most of the fields a pretty descriptive, let&#8217;s take a look at one, important thing- <strong>variables</strong>.</p>
<p>As we can see, we can inject variables into the email subject, or content by simply specifying them with a dollar sign inside curly braces, for example: <em>{$someVariable}</em>. This way, we can specify dynamic values for each recipient, like name and company in our example.</p>
<p>In the next lines, we simply send the request to the MailerSend API, and if the response status code is <strong>202 Accepted</strong>, then the email was sent successfully:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504295 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9.png" alt="Screenshot shows an example email send with MailerSend API using Ktor client." width="446" height="260" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9.png 446w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9-300x175.png 300w" sizes="auto, (max-width: 446px) 100vw, 446px" /></p>
<p>&nbsp;</p>
<p>Of course, in order to make it work, let&#8217;s invoke our function inside the <em>configureClient</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">runBlocking {
  sendSimpleMessage(mailerSendClient, baseUrl, token)
}
</pre>
<h2>Send Emails With Templates</h2>
<p>At this point, we already know how to send transactional emails with Ktor and MailerSend. Moreover, we&#8217;ve seen how to send HTML content, which is a great way to customize the template.</p>
<p>Nevertheless, if you&#8217;d like to learn how to <strong>make your life a bit easier</strong> and use a <strong>graphic builder for templates</strong>, then you&#8217;re gonna like this paragraph.</p>
<h3>Prepare Template Using MailerSend Builder</h3>
<p>As the first step, let&#8217;s navigate to the templates page: <a href="https://app.mailersend.com/templates" target="_blank" rel="noopener">https://app.mailersend.com/templates</a>.</p>
<p>Nextly, let&#8217;s click <strong>Create template</strong> button and select <strong>Drag &amp; drop</strong> editor option:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504296 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10.png" alt="Screenshot presents 3 options we can select when creating a new template: drag &amp; drop editor, rich-text editor and HTML editor." width="980" height="687" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10.png 980w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10-300x210.png 300w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10-768x538.png 768w" sizes="auto, (max-width: 980px) 100vw, 980px" /></p>
<p>&nbsp;</p>
<p>This way, we&#8217;re redirected to the <strong>Template gallery</strong>, which contains ~50 predefined templates, which we can adjust to our needs. In this tutorial, we will select the <strong>Reset password</strong>:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504297 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11.png" alt="Image presents MailerSend template gallery with highlited Reset passoword template." width="1250" height="763" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11.png 1250w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-300x183.png 300w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-1024x625.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-768x469.png 768w" sizes="auto, (max-width: 1250px) 100vw, 1250px" /></p>
<p>&nbsp;</p>
<p>After we click <strong>Choose</strong>, we&#8217;re redirected to the builder page, where we can make adjustments:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504298" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12.png" alt="Screenshot shows MailerSend template builder and edited template." width="500" height="563" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12.png 662w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-266x300.png 266w" sizes="auto, (max-width: 500px) 100vw, 500px" /></p>
<p>&nbsp;</p>
<p>As we can see, when using the builder, we need to encapsulate variables with <strong>double curly brackets</strong>.</p>
<p>When we finish, let&#8217;s click the <strong>Save &amp; Publish</strong> button and <strong>write down the Template ID</strong> on the next page- we will need it later.</p>
<h3>Adjust EmailRequest Class</h3>
<p>With that being done, let&#8217;s get back to the Ktor project and edit the EmailRequest class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@JsonInclude(JsonInclude.Include.NON_NULL)
data class EmailRequest(
    val from: Recipient,
    val to: List&lt;Recipient&gt;,
    val subject: String,
    @JsonProperty("template_id") val templateId: String,
    val personalization: List&lt;CustomPersonalization&gt;
) {
    data class Recipient(
        val email: String,
        val name: String
    )

    data class CustomPersonalization(
        val email: String,
        val data: PersonalizationData
    ) {
        data class PersonalizationData(
            val name: String,
            @JsonProperty("my_super_generated_code") val code: String
        )
    }
}
</pre>
<p>This time, instead of specifying the content manually, we simply pass the <strong>template identifier</strong> and a <strong>list of personalizations</strong>.</p>
<p>In our case, the desired JSON looks, as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "from": {
    "email": "example@test.codersee.com",
    "name": "Codersee"
  },
  "to": [
    {
      "email": "example@test.codersee.com",
      "name": "Pjoter"
    }
  ],
  "subject": "Please Reset Your Password",
  "templateId": "v69oxl587pzl785k",
  "personalization": [
    {
       "email": "example@test.codersee.com",
       "data": {
         "name": "Pjoter",
         "code": "f7fcc37c-4b7a-4919-aa91-a5ac7edd55d7"
       }
     }
  ]
}

</pre>
<h3>Implement Sending Functionality</h3>
<p>With all of that prepared, let&#8217;s implement the <em>sendMessageUsingTemplate</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendMessageUsingTemplate(
    mailerSendClient: HttpClient,
    baseUrl: String,
    token: String
) {
    val subject = "Please Reset Your Password"

    val emailRequest = EmailRequest(
        from = EmailRequest.Recipient(
            email = "example@test.codersee.com",
            name = "Codersee"
        ),
        to = listOf(
            EmailRequest.Recipient(
                email = "example@test.codersee.com",
                name = "Pjoter"
            )
        ),
        subject = subject,
        templateId = "v69oxl587pzl785k",
        personalization = listOf(
            EmailRequest.CustomPersonalization(
                email = "example@test.codersee.com",
                data = EmailRequest.CustomPersonalization.PersonalizationData(
                    name = "Pjoter",
                    code = UUID.randomUUID().toString()
                )
            )
        )
    )

    val response = sendSingleEmail(
        mailerSendClient = mailerSendClient,
        url = "$baseUrl/email",
        token = token,
        emailRequest = emailRequest
    )

    if (response.status == HttpStatusCode.Accepted)
        println("Email sent successfully.")
    else
        println("Error when sending email.")
</pre>
<p>As we can see, the logic itself remains almost exactly the same and the only thing, which changes, is the payload we send.</p>
<p>Lastly, let&#8217;s put the following in the <em>configureClient </em>and rerun the application:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">runBlocking {
  sendSimpleMessage(mailerSendClient, baseUrl, token)
}</pre>
<p>As a result, we should see the message &#8220;Email sent successfully.&#8221; and the following email in our inbox:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504301" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1.png" alt="Image shows an example email from inbox." width="550" height="556" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1.png 786w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1-297x300.png 297w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1-768x777.png 768w" sizes="auto, (max-width: 550px) 100vw, 550px" /></p>
<h2>Handling ErrorsEmails With Templates</h2>
<p>I simply couldn&#8217;t finish this article about sending transactional emails with Ktor and MailerSend without showing <strong>how to handle errors</strong>.</p>
<p>And although we try our best to avoid them, sooner or later they will pop up. Thankfully, MailerSend API informs us in a pretty neat way about any issues. For example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
    "message": "The template_id must be an integer. (and 2 more errors)",
    "errors": {
        "template_id": [
            "The template_id must be an integer."
        ],
        "to.0.email": [
            "The to.0.email field is required."
        ],
        "variables.0.email": [
            "The variables.0.email field does not exist in to.*.email."
        ]
    }
}
</pre>
<h3>Create ErrorResponse</h3>
<p>As the first step, let&#8217;s implement the ErrorResponse class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class ErrorResponse(
  val message: String,
  val errors: Map&lt;String, List&lt;String&gt;&gt;
)
</pre>
<p>We will use this simple data class to deserialize JSON response into the object.</p>
<h3>Implement handleError</h3>
<p>Nextly, let&#8217;s add the <em>handleError</em> function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun handleError(response: HttpResponse) {
    val statusCode = response.status.value
    val errorBody =  response.body&lt;ErrorResponse&gt;()
    println("Email sending failed with status code $statusCode and message '${errorBody.message}'. Errors:")

    errorBody.errors.forEach { (fieldName, fieldErrors) -&gt;
        println("  * field name: [$fieldName]. Messages:")
        fieldErrors.forEach { error -&gt; println("    - $error") }
    }
}

</pre>
<p>As we can see, this function takes the HttpResponse from MailerSend API and parses the JSON into the ErrorResponse instance. Thanks to that we can iterate and display all the errors.</p>
<p>Of course, as the last step, we need to modify our conditional statement, to make use of this snippet:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">if (response.status == HttpStatusCode.Accepted)
  println("Email sent successfully.")
else 
  println("Error when sending email.")
</pre>
<h2>Sending Emails With Ktor And MailerSend Summary</h2>
<p>And that&#8217;s all for this article about <strong>how to send transactional emails using Ktor, Kotlin, and MailerSend</strong>.</p>
<p>As always, you can find the source code in this <a href="https://github.com/codersee-blog/kotlin-ktor-mailersend-transactional-emails" target="_blank" rel="noopener">GitHub repository.</a></p>
<p>Happy to hear your <strong>thoughts, feedback, or ideas in the comments</strong> 🙂</p>
<p>The post <a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/">Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>How to Send Emails with Spring Boot and Kotlin</title>
		<link>https://blog.codersee.com/how-to-send-emails-with-spring-boot-and-kotlin/</link>
					<comments>https://blog.codersee.com/how-to-send-emails-with-spring-boot-and-kotlin/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Mon, 05 Oct 2020 09:50:42 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">http://codersee.com/?p=1410</guid>

					<description><![CDATA[<p>In this tutorial, we will learn how to send emails using JavaMailSender in Spring Boot Kotlin application with the Gmail SMTP server.</p>
<p>The post <a href="https://blog.codersee.com/how-to-send-emails-with-spring-boot-and-kotlin/">How to Send Emails with Spring Boot and Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hello dear reader <span data-offset-key="2eavg-0-0">?</span>. I&#8217;m pleased to welcome you to our <strong>sixth </strong>article. I am so happy and excited that our community is growing at this rate and that I can share my knowledge with you.</p>



<p>In this tutorial, we will learn how to send emails using <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/mail/javamail/JavaMailSender.html" target="_blank" rel="noopener noreferrer">JavaMailSender</a> 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).</p>



<h2 class="wp-block-heading" id="h-2-imports">2. Imports</h2>



<p>Let&#8217;s start with adding the required dependencies to our existing Spring Boot project:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="groovy" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  
  implementation("org.springframework.boot:spring-boot-starter-mail")
  implementation("org.springframework.boot:spring-boot-starter-web")
</pre>



<p>Thanks to <strong>spring-boot-starter-mail</strong>, we will be able to send emails using <span class="description"><strong>Java Mail</strong> and Spring Framework&#8217;s <strong>JavaMailSender</strong>.</span></p>



<h2 class="wp-block-heading" id="h-3-configure-javamailsender">3. Configure JavaMailSender</h2>



<p>As the next step, let&#8217;s configure <strong>JavaMailSender</strong>. There are basically two ways we can do this- using the application properties file, as well as manually defining the <strong>@Bean</strong> of <strong>JavaMailSender</strong> type.</p>



<h3 class="wp-block-heading" id="h-3-1-configure-javamailsender-using-configuration-file">3.1. Configure JavaMailSender Using Configuration File</h3>



<p>Let&#8217;s start with the easier way (at least in my opinion) and add the following configuration to our <strong>application.yaml</strong> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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}
</pre>



<p>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:</p>



<ul class="wp-block-list">
<li><em>MAIL_SENDER_HOST</em>&#8211; smtp.gmail.com</li>



<li><em>MAIL_SENDER_PORT</em>&#8211; 587</li>



<li><em>MAIL_SENDER_USERNAME</em>&#8211; our Gmail email</li>



<li><em>MAIL_SENDER_PASSWORD</em>&#8211; our password</li>



<li><em>MAIL_SENDER_PROTOCOL</em>&#8211; smtp</li>



<li><em>MAIL_SENDER_DEBUG</em> &#8211; true</li>



<li><em>MAIL_SENDER_AUTH</em>&#8211; true</li>



<li><em>MAIL_SENDER_STARTTLS_ENABLE</em>&#8211; true</li>
</ul>



<h3 class="wp-block-heading" id="h-3-2-configure-javamailsender-bean-definition">3.2. Configure JavaMailSender @Bean Definition</h3>



<p>Sometimes, we would like to define the configuration bean manually. Let&#8217;s start with implementing <strong>MailSenderProperties</strong> class, which will bind and validate properties from <strong>application.yaml</strong> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@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
)
</pre>



<p>The <em><strong>@ConstructorBinding</strong></em> annotation will bind the external properties to the constructor parameters.</p>



<p>As the next step, let&#8217;s edit the <strong>application.yaml</strong> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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}
</pre>



<p>Please notice, that the prefix of the properties has to match the prefix set inside <em><strong>@ConfigurationProperties</strong></em> annotation.</p>



<p>After that, let&#8217;s create the <strong>MailSenderConfig</strong> class and annotate it with <em><strong>@EnableConfigurationProperties</strong></em>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Configuration
@EnableConfigurationProperties(MailSenderProperties::class)
class MailSenderConfig(
    private val mailSenderProperties: MailSenderProperties
) 
</pre>



<p>The <em><strong>@EnableConfigurationProperties</strong></em> annotation enables support for <em><strong>@ConfigurationProperties</strong></em> annotated beans.</p>



<p>With that being done, we can finally define JavaMailSender bean:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@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
}
</pre>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<h2 class="wp-block-heading" id="h-4-allow-less-secure-apps-in-gmail-settings">4. Allow Less Secure Apps In Gmail Settings</h2>



<p>But before we will send our first email, we have to make sure, that we won&#8217;t be blocked by our SMTP server. To do that in Gmail, please follow this <a href="https://myaccount.google.com/lesssecureapps" target="_blank" rel="noopener noreferrer">link</a> and turn the access on:<br><img loading="lazy" decoding="async" class="alignnone size-medium wp-image-1415" src="http://blog.codersee.com/wp-content/uploads/2020/10/Screenshot-from-2020-09-30-19-14-45.png" alt="Photo contains the screenshot showing allow less secure apps page in gmail settings" width="754" height="283" srcset="https://blog.codersee.com/wp-content/uploads/2020/10/Screenshot-from-2020-09-30-19-14-45.png 754w, https://blog.codersee.com/wp-content/uploads/2020/10/Screenshot-from-2020-09-30-19-14-45-300x113.png 300w" sizes="auto, (max-width: 754px) 100vw, 754px" /><br>We might also receive the email asking us to confirm this action:<br><img loading="lazy" decoding="async" class="alignnone size-medium wp-image-1418" src="http://blog.codersee.com/wp-content/uploads/2020/10/3.png" alt="Photo contains the screenshot showing email with confirmation request from Gmail" width="603" height="371" srcset="https://blog.codersee.com/wp-content/uploads/2020/10/3.png 603w, https://blog.codersee.com/wp-content/uploads/2020/10/3-300x185.png 300w" sizes="auto, (max-width: 603px) 100vw, 603px" /></p>



<h2 class="wp-block-heading" id="h-5-send-emails">5. Send Emails</h2>



<h3 class="wp-block-heading" id="h-5-1-send-simple-email">5.1. Send Simple Email</h3>



<p>Let&#8217;s start simply by creating the <strong>EmailSenderService</strong> containing one function:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@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)
  }
}
</pre>



<p>This uncomplicated function takes the subject, text, and the target email as the parameters and sends the given simple mail message using injected <strong>JavaMailSender</strong> instance.</p>



<h3 class="wp-block-heading" id="h-5-2-send-email-using-template">5.2. Send Email Using Template</h3>



<p>Sometimes, we would like to prepare one reusable template and personalize it depending on our needs. Let&#8217;s create a <strong>TemplateConfig</strong> class and define the template bean:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@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
    }
}
</pre>



<p>To make our template eligible for personalization, we&#8217;ve used Java String formatting specifier- <strong>%s</strong>, which will allow us to pass the name of the user.</p>



<p>As the next step, let&#8217;s inject the template to the previously created service:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Service
class EmailSenderService(
    private val emailSender: JavaMailSender,
    private val template: SimpleMailMessage
)
</pre>



<p>And finally, let&#8217;s create the <strong>sendEmailUsingTemplate</strong> function, which will take the user email and name as the parameter:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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)
}
</pre>



<h3 class="wp-block-heading" id="h-5-2-send-email-with-attachment">5.2. Send Email With Attachment</h3>



<p>Now, let&#8217;s learn how to send the email containing an attachment. Let&#8217;s create a file named <strong>file.txt</strong> and let&#8217;s place it inside the resources directory of the project. Then, let&#8217;s inject the file inside our service:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class EmailSenderService(
    private val emailSender: JavaMailSender,
    private val template: SimpleMailMessage,
    @Value("classpath:file.txt")
    private val resourceFile: Resource
)
</pre>



<p>As the last step, let&#8217;s implement the function, which will take the target email as the argument:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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)
}
</pre>



<h2 class="wp-block-heading" id="h-5-create-a-test-controller">5. Create a Test Controller</h2>



<p>Finally, we can create the example controller and prepare some endpoints for testing purposes:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@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()
    }
}
</pre>



<p>Also, please remember to implement <strong>EmailRequest</strong> class used in the above functions:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class EmailRequest(
    val subject: String?,
    val targetEmail: String?,
    val text: String?,
    val name: String?
)
</pre>



<h2 class="wp-block-heading" id="h-5-testing-with-curl">5. Testing with Curl</h2>



<p>And finally, we can run our application and check if everything works fine using the curl command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">curl -H "Content-Type: application/json" \
  -d '{"subject":"Example subject", "targetEmail":"your@mail.com", "text":"Example content."}' \
  http://localhost:8080/api/email
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">curl -H "Content-Type: application/json" \
  -d '{"name":"Piotr","targetEmail":"your@mail.com"}' \
  http://localhost:8080/api/email/template
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">curl -H "Content-Type: application/json" \
  -d '{"targetEmail":"your@mail.com"}' \
  http://localhost:8080/api/email/attachment
</pre>



<p>Please remember to change the <strong><em>targetEmail</em></strong> in the requests to the valid one. If everything has been set up correctly, then we should receive three emails to our inbox.</p>



<h2 class="wp-block-heading" id="h-6-summary">6. Summary</h2>



<p>In this step by step tutorial, we&#8217;ve learned how to send emails using <strong>JavaMailSender</strong> in a <strong>Spring Boot Kotlin</strong> application. I hope that you&#8217;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 <a href="https://www.facebook.com/codersee/" target="_blank" rel="noopener noreferrer"><strong>page</strong></a>, <a href="https://www.facebook.com/groups/622361565094117" target="_blank" rel="noopener noreferrer"><strong>group</strong></a>, or <strong><a href="http://codersee.com/contact/" target="_blank" rel="noopener noreferrer">contact</a> </strong>form). I really appreciate each suggestion that I get from you.</p>



<p>For the source code of the project, please visit our project on <a href="https://github.com/codersee-blog/kotlin-spring-boot-mail-sender" target="_blank" rel="noopener noreferrer"><strong>GitHub</strong></a>.</p>
<p>The post <a href="https://blog.codersee.com/how-to-send-emails-with-spring-boot-and-kotlin/">How to Send Emails with Spring Boot and Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/how-to-send-emails-with-spring-boot-and-kotlin/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-05-14 10:34:43 by W3 Total Cache
-->