Skip to content

Instantly share code, notes, and snippets.

@xthezealot
Last active January 29, 2025 14:59
Show Gist options
  • Save xthezealot/1922ed0a3c1266e3e1bca80f62175f36 to your computer and use it in GitHub Desktop.
Save xthezealot/1922ed0a3c1266e3e1bca80f62175f36 to your computer and use it in GitHub Desktop.
Crystal SMTP Client

Crystal SMTP Client

Usage

smtp = SmtpClient.new("SMTP_HOST")
begin
  smtp.authenticate("SMTP_USERNAME", "SMTP_PASSWORD")
  smtp.send_email(
    from: "FROM_EMAIL",
    to: "TO_EMAIL",
    subject: "MAIL_SUBJECT",
    body: "MESSAGE"
  )
ensure
  smtp.close
end
require "base64"
require "openssl"
require "socket"
class SMTPClient
CRLF = "\r\n"
def initialize(@host : String, @port : Int32 = 587)
@socket = TCPSocket.new(@host, @port)
@socket.tcp_nodelay = true
@ssl_socket = nil
read_response
end
def authenticate(username : String, password : String)
send_command("EHLO localhost")
send_command("STARTTLS")
@ssl_socket = OpenSSL::SSL::Socket::Client.new(@socket)
send_command("EHLO localhost")
send_command("AUTH LOGIN")
send_command(Base64.strict_encode(username.strip))
send_command(Base64.strict_encode(password.strip))
end
def send_email(from : String, to : String, subject : String, body : String)
send_command("MAIL FROM:<#{from}>")
send_command("RCPT TO:<#{to}>")
send_command("DATA")
send_command("From: #{from}#{CRLF}To: #{to}#{CRLF}Subject: #{subject}#{CRLF}#{CRLF}#{body}#{CRLF}.#{CRLF}")
end
private def send_command(command : String)
socket = @ssl_socket || @socket
socket << command << CRLF
socket.flush
read_response
end
private def read_response : String
socket = @ssl_socket || @socket
responses = [] of String
while line = socket.gets
line = line.chomp
responses << line
break unless line.starts_with?(/\d{3}-/)
end
response = responses.last
raise "SMTP Error: #{response}" if response.starts_with?(/[45]/)
response
end
def close
send_command("QUIT") rescue nil
@ssl_socket.try(&.close)
@socket.close
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment