Page 1 of 1

libSMTP

Posted: Sun Feb 13, 2022 6:11 pm
by Emily-Elizabeth
This is an event-driven SMTP library. This is just the first rough draft, no error handling, etc, but would like to get feedback. There are three public commands that you call SMTPConnect, SMTPSend, and SMTPDisconnect.
SMTPConnect has three callbacks SMTPConnected, SMTPRequestAuthenticationMethod(), and SMTPLoggedIn.
SMTPSend has four callbacks SMTPRequestSender(), SMTPRequestRecipient(), SMTPRequestDataLine() and SMTPMessageSent
SMTPDisconnect has one callback SMTPDisconnected

So a typical workflow would be something like:
SMTPConnect
- SMTPConnected
- SMTPRequestAuthenticationMethod()
- SMTPLoggedIn

In the SMTPLoggedIn callback you would call:
SMTPSend
- SMTPRequestSender()
- SMTPRequestRecipient()
- SMTPRequestDataLine()
- SMTPMessageSent [you can call SMTPSend again from here to send another message, or SMTPDisconnect]

SMTPDisconnect
- SMTPDisconnected

Code: Select all

--- public commands
// SMTPConnect
// SMTPSend
// SMTPDisconnect


--- callbacks
// SMTPConnected
// SMTPRequestAuthenticationMethod()
// SMTPLoggedIn
// SMTPRequestSender()
// SMTPRequestRecipient()
// SMTPRequestDataLine()
// SMTPMessageSent
// SMTPDisconnected


--- contants used for socket timeouts
constant kTwoMinutes   = 120000
constant kThreeMinutes = 180000
constant kFiveMinutes  = 300000
constant kTenMinutes   = 600000


local sCallback
local sSMTPReply
local sCurrentCommand


on SMTPConnect serverAddress, serverPort, useSSL, callback
   local sender
   put serverAddress & ":" & serverPort & "|libSMTP" into sender
   put EMPTY into sSMTPReply[sender]
   put EMPTY into sCurrentCommand[sender]
   put callback into sCallback[sender]
   if (useSSL) then
      open secure socket to sender with message "libSMTPRead"
   else
      open socket to sender with message "libSMTPRead"
   end if
end SMTPConnect


on SMTPDisconnect sender
   libSMTPWrite sender, "QUIT", kFiveMinutes   
end SMTPDisconnect


on SMTPSend sender
   dispatch function "SMTPRequestSender" to sCallback[sender] with sender
   libSMTPWrite sender, "MAIL FROM:<" & the result & ">", kFiveMinutes   
end SMTPSend


on libSMTPRead sender
   read from socket sender until CRLF with message "libSMTPGotData"
end libSMTPRead


on libSMTPGotData sender, data
   put data after sSMTPReply[sender]
   if (char 4 of data = "-") then  // multi-line reply
      read from socket sender until CRLF with message "libSMTPGotData"
   else
      switch (char 1 to 3 of sSMTPReply[sender])
         case 220  // <domain> service ready
            dispatch "SMTPConnected" to sCallback[sender] with sender, sSMTPReply[sender]
            libSMTPWrite sender, "EHLO" && hostAddress(sender), kFiveMinutes
            break
         case 221  //
            close socket sender
            dispatch "SMTPDisconnected" to sCallback[sender] with sender
            break
         case 235  // password successful
            dispatch "SMTPLoggedIn" to sCallback[sender] with sender
            break
         case 250  // requested mail action okay, completed
            if (sCurrentCommand[sender] = "EHLO") then
               local authMethods
               put libSMTPFindAuthMethods(sSMTPReply[sender]) into authMethods
               dispatch function "SMTPRequestAuthenticationMethod" to sCallback[sender] with sender, authMethods
               libSMTPWrite sender, "AUTH" && the result, kFiveMinutes
            else if (sCurrentCommand[sender] = "MAIL") then
               libSMTPGetNextRecipient sender
            else if (sCurrentCommand[sender] = "RCPT") then
               libSMTPGetNextRecipient sender
            else if (sCurrentCommand[sender] = ".") then
               dispatch "SMTPMessageSent" to sCallback[sender] with sender
            end if
            break
         case 251
            if (sCurrentCommand[sender] = "RCPT") then
               dispatch "SMTPInvalidRecipient" to sCallback[sender] with sender
               libSMTPGetNextRecipient sender
            end if
            break
         case 354  // start mail input; end with <CRLF>.<CRLF>
            if (sCurrentCommand[sender] = "DATA") then
               libSMTPGetNextDataLine sender
            end if
            break
         default
            put sSMTPReply[sender]
            close socket (line 1 of the openSockets)
      end switch
   end if
end libSMTPGotData


on libSMTPWrite sender, data, timeout
   put EMPTY into sSMTPReply[sender]
   put word 1 of data into sCurrentCommand[sender]
   set the socketTimeoutInterval to timeout
   write data & CRLF to socket sender with message "libSMTPRead"
end libSMTPWrite


on libSMTPWriteDataLine sender, data, timeout
   set the socketTimeoutInterval to timeout
   if (data = ".") then
      write ".." & CRLF to socket sender with message "libSMTPGetNextDataLine"
   else
      write data & CRLF to socket sender with message "libSMTPGetNextDataLine"
   end if
end libSMTPWriteDataLine


on libSMTPGetNextDataLine sender
   dispatch function "SMTPRequestDataLine" to sCallback[sender] with sender
   if (the result is FALSE) then
      libSMTPWrite sender, ".", kTenMinutes
   else
      libSMTPWriteDataLine sender, the result, kThreeMinutes
   end if
end libSMTPGetNextDataLine


on libSMTPGetNextRecipient sender
   dispatch function "SMTPRequestRecipient" to sCallback[sender] with sender
   if (the result is FALSE) then
      libSMTPWrite sender, "DATA", kTwoMinutes
   else
      libSMTPWrite sender, "RCPT TO:<" & the result & ">", kFiveMinutes
   end if
end libSMTPGetNextRecipient
   
   
   function libSMTPFindAuthMethods data
   local results
   repeat for each line tLine in data
      if (word 1 of tLine = "250-AUTH") then
         put word 2 to -1 of tLine into results
      else if (word 2 of tLine = "AUTH") then
         put word 3 to -1 of tLine into results
      end if
   end repeat
   return results
end libSMTPFindAuthMethods

Re: libSMTP

Posted: Sat Feb 26, 2022 2:36 am
by mwieder
Nice. Looks like a good start.
I'm surprised "callback" isn't a reserved word, but there you go.

Re: libSMTP

Posted: Fri Feb 17, 2023 7:24 pm
by cmhjon
Is there a way to pass HMTL commands such as bolding certain words in the email that is generated and sent?

Best regards,
Jon

Re: libSMTP

Posted: Sat Feb 18, 2023 5:19 am
by Emily-Elizabeth
That would be done in your MIME message that you'd create before sending it through SMTP.

Re: libSMTP

Posted: Sat Feb 18, 2023 1:13 pm
by cmhjon
Hi Emily-Elizabeth,

Thank you for the reply. How does one create a MIME message in LC?

Best regards,
Jon :-)

Re: libSMTP

Posted: Sat Feb 18, 2023 4:53 pm
by Emily-Elizabeth
MIME is just plain text, but needs to be in a specific format. For more information take a look at this wikipedia article https://en.wikipedia.org/wiki/MIME and if you're really bored, the six RFCs for MIME are linked at the beginning of the article.

Re: libSMTP

Posted: Mon Feb 20, 2023 2:11 pm
by cmhjon
Hi Emily-Elizabeth,

I tried digesting that link and what little sense I could make of it, I tried putting "MIME-Version: 1.0" into he first line of the body of the email to be sent but all I get is an email with that text just added as part of the body. Any subsequent HTML codes don't do anything.

Do you have any LC code examples on what I would need to do to get this to work?

Best regards,
Jon

Re: libSMTP

Posted: Mon Feb 20, 2023 5:29 pm
by Emily-Elizabeth
I would have to look in to it, but currently working on a project, so it'd have to wait.

Re: libSMTP

Posted: Mon Feb 20, 2023 7:05 pm
by cmhjon
Hi Emily-Elizabeth,

I would be most grateful for any help you could provide as your time allows.

Best regards,
Jon :-)