8

I'm currently creating my application using Ktor Netty Engine

I searched the docs for any feature to handle sending emails when a user sends a request to my server but found nothing.

post("/api/v1/auth") {
    // TODO send email when request is sent!
}
Arrowsome
  • 2,649
  • 3
  • 10
  • 35

3 Answers3

8

There is a java dependency available to be used in Ktor apache-email-commons

implementation("org.apache.commons:commons-email:1.5")

And then using an SMTP server e.g. Gmail:

val email = SimpleEmail()
email.hostName = "smtp.googlemail.com"
email.setSmtpPort(465)
email.setAuthenticator(DefaultAuthenticator("email-account", "account-password"))
email.isSSLOnConnect = true
email.setFrom("sender-email-account")
email.subject = "email-subject"
email.setMsg("message-content")
email.addTo("target-email-address")
email.send()
Arrowsome
  • 2,649
  • 3
  • 10
  • 35
  • You have to turn off "Less secure app access" if you use smtp.googlemail.com, otherwise you'll get "Someone just used your password to try to sign in to your account from a non-Google app". In addition, this setting is not available for accounts with 2-Step Verification enabled. This approach works, but it's less secure than OAuth2 via web-services. – Pitos Feb 07 '22 at 17:32
  • 1
    As of May 2022, google no longer supports "Less secure app access" for non-paid workspace accounts. – Erik B Oct 28 '22 at 21:54
2

There is no built-in feature in Ktor for sending emails.

Aleksei Tirman
  • 4,658
  • 1
  • 5
  • 24
0

Check out this library:

// https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail implementation("com.sun.mail:jakarta.mail:2.0.1")

it's newer than javax.mail library

Example code in kotlin:

import com.sun.mail.util.MailConnectException
import jakarta.mail.*
import jakarta.mail.internet.InternetAddress
import jakarta.mail.internet.MimeMessage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Properties
import java.util.Date

companion object {
        const val GOOGLE_SMTP_HOST = "smtp.gmail.com"
        const val ZOHO_SMTP_HOST = "smtp.zoho.in"
    }
    private val props = Properties().apply {
        this["mail.smtp.host"] = ZOHO_SMTP_HOST
        this["mail.smtp.port"] = "587"
        this["mail.smtp.auth"] = "true"
        this["mail.smtp.starttls.enable"] = "true"
    }
    private val emailUsername = System.getenv("EMAIL_USERNAME") ?: throw IllegalStateException("EMAIL_USERNAME env should not be null.")
    private val emailPassword = System.getenv("EMAIL_PASSWORD") ?: throw IllegalStateException("EMAIL_PASSWORD env should not be null.")
    private val fromEmail = System.getenv("FROM_EMAIL") ?: emailUsername

    private val session: Session = Session.getInstance(props, object : Authenticator() {
        override fun getPasswordAuthentication(): PasswordAuthentication {
            val username = emailUsername
            val password = emailPassword
            return PasswordAuthentication(username, password)
        }
    })
    override suspend fun sendEmail(emailMessage: EmailMessage): Boolean = withContext(Dispatchers.IO) {
        return@withContext try {
            val message = MimeMessage(session)
            val from = fromEmail
            message.setFrom(InternetAddress(from))
            message.setRecipients(
                Message.RecipientType.TO,
                emailMessage.to.lowercase().trim()
            )
            message.subject = emailMessage.subject
            message.sentDate = Date()
            message.setText(emailMessage.body)
            Transport.send(message)
            true
        } catch (mex: MessagingException) {
            println("send failed, exception: $mex")
            false
        } catch (e: MailConnectException) {
            println("email send failed, exception: $e")
            false
        }
        catch (e: java.net.ConnectException) {
            println("Connection failed: $e")
            false
        }
        catch (e: Exception) {
            e.printStackTrace()
            println("Unhandled exception while send email ${e.javaClass.name} from ${e.javaClass.packageName}")
            false
        }
    }
Ahmed Hnewa
  • 1,185
  • 1
  • 4
  • 14