SMTPS - sending emails via gmail using SSL/TLS

Just starting out? Need help? Post your questions and find answers here.
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

I have just finished a project that required me to send an email from an appplication using googles gmail
smtp.gmail.com

Writing the SMTP dialog with error handling can be time consuming, but not too much trouble to implement on port 25. Google however only accepts SMTP email on port 465 over an SSL encrypted connection. This is a large popthole, because the implementation of SLL requires intimate knowledge off all kinds of things most of us could care less about.

After a great deal of searching I found socket tools www.catalys.com and an open source library, cryptlib that provides this functionality.

I have detailed how to use cryptlib and provided headers and source code examples here
http://www.coastrd.com

I would appreciate it if someone could make the simple conversion from powerbasic to purebasic so I can offer the code for this excellent compiler.
Fred
Administrator
Administrator
Posts: 18152
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Fred »

Just start the conversion yourself and if you don't success, post the code part where you are locked.
RE-A
User
User
Posts: 39
Joined: Thu Aug 21, 2008 4:19 pm
Location: Belgium
Contact:

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by RE-A »

Mike, I agree with fred. I successfully translated a rather big project from powerbasic to purebasic without any problems. It will be difficult at first but it get easier when you get used to the syntax.
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

Be happy to, but I don't have a purebasic compiler. Perhaps I should have a good stab at it and then post the code for comments?
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Foz »

... you want to work on doing code translations without using the compiler?

If you want to use PureBasic, then by all means do so, but buy it.

If you just want to provide generic libraries for coders, I'd suggest creating C libraries that can then be interfaced with anything.
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

Yes did that. I was offering to support this language over powerbasic if you guys are willing to give a few minutes of your time
Fred
Administrator
Administrator
Posts: 18152
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Fred »

Just use the demo version.
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

A DEMO! holy smoke, you mean there is a demo for this language!
In ten years, powerbasic could not come up with one, so I just assumed it was a physical impossability...

Demo installed.
FIrst problem: converting function prototypes:
C (http://www.coastrd.com/cryptlib-h)
BASIC (http://www.coastrd.com/smtps/cryptlib/c ... header-inc)

Code: Select all

DECLARE FUNCTION cryptInit                  STDCALL LIB "cl32.dll" ALIAS "cryptInit"() AS LONG

DECLARE FUNCTION cryptCreateSession         STDCALL LIB "cl32.dll" ALIAS "cryptCreateSession"          (_
  BYVAL pSession     AS LONG PTR,_  
  BYVAL cryptUser    AS LONG,_ 
  BYVAL SessionType  AS LONG ) AS LONG 

DECLARE FUNCTION cryptSetAttributeString    STDCALL LIB "cl32.dll" ALIAS "cryptSetAttributeString"     (_
  BYVAL hCrypt       AS LONG,_  
  BYVAL CryptAttType AS LONG,_ 
  BYVAL pBuff        AS DWORD,_ 
  BYVAL StrLen       AS LONG ) AS LONG 
second problem:
Calling functions in a statically linked dll (http://www.coastrd.com/smtps/cryptlib/basic-smtps)

Code: Select all

      RetVal = CryptCreateSession( VARPTR(hSess), %CRYPT_UNUSED, %CRYPT_SESSION_SSL )
      RetVal = CryptSetAttributeString( hSess, CRYPT_SESSINFO_SERVER_NAME, STRPTR(sSrvr), LEN(sSrvr) ) 
Third problem:
Sleep() without calling windows API (restricted in demo version)

Code: Select all

    '- Recover response 
    sReply = "" 
    WHILE PARSECOUNT(sReply, $CRLF)-1  <  nRetLn 
      Totms  = 0 
      DO  
        SLEEP 20 ' Wait for a response  
        Totms = Totms + 20 ' 
        IF Totms > %SMTP_RESPONSE_TIMEOUT THEN 
          sErr = "Response timeout >" + STR$(%SMTP_RESPONSE_TIMEOUT) + "m/s" 
          FUNCTION = -28 : EXIT FUNCTION 
        END IF ' 
PRINT #hDbg, STR$(Totms) + "m/s" ', LEN(sReply)=" +STR$(LEN(sReply))
  
        RetVal = CryptPopData( hCrypt, STRPTR(sBuff), LEN(sBuff), VARPTR(BytesReply) )  
        IF RetVal <> %CRYPT_OK THEN 
          sErr = "CryptPopData ERROR: "+Err2Str(RetVal)+" - "+ErrExStr(hCrypt) 
          FUNCTION = -29 : EXIT FUNCTION 
        ELSEIF BytesReply > 0 THEN 
          sReply = sReply + LEFT$(sBuff, BytesReply) ' 
          Last = LEN(sReply) ' 
  PRINT #hDbg, "Rply:" + STR$(BytesReply) + " Bytes: " + $CRLF + LEFT$(sBuff, BytesReply) 
          pByte = STRPTR(sReply) ' Check last line for SMTP code follwed by space
          IF Last > 5 AND @pByte[Last-1] = 10 AND @pByte[Last-2] = 13 THEN ' CRLF 
            FOR k = 3 TO Last ' PRINT #hDbg, "CharNum=" + STR$(Last-k+1) + ", " + CHR$(@pByte[Last-k]) 
              IF @pByte[Last-k] = 10 AND @pByte[Last-k+4] = 32 THEN EXIT DO ' Space not a hyphen "-", Response complete 
              IF k = last            AND @pByte[Last-k+3] = 32 THEN EXIT DO ' Space not a hyphen "-", Response complete 
            NEXT
          END IF   
        END IF  
      LOOP ' PRINT #hDbg, BytesToHexPtr( STRPTR(sBuff), BytesReply )
    WEND 

User avatar
Demivec
Addict
Addict
Posts: 4257
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Demivec »

Mike Trader wrote:Third problem:
Sleep() without calling windows API (restricted in demo version)
Use the native Delay().

Here's a rough workover of your function as well (just for kicks) :wink: :

Code: Select all

  ;- Recover response 
  sReply.s = "" 
  While PARSECOUNT(sReply, #CRLF$)-1  <  nRetLn 
    Totms  = 0 
    ;Do
    Repeat  
      ;SLEEP 20 ; Wait for a response  
      Delay(20) ; Wait for a response  
      Totms = Totms + 20 ; 
      If Totms > #SMTP_RESPONSE_TIMEOUT
        sErr = "Response timeout >" + Str(#SMTP_RESPONSE_TIMEOUT) + "m/s" 
        ;function = -28 : EXIT function 
        ProcedureReturn -28
      EndIf ; 
      PRINT #hDbg, Str(Totms) + "m/s" ;, LEN(sReply)=" +str(LEN(sReply))
      
      RetVal = CryptPopData( hCrypt, STRPTR(sBuff), Len(sBuff), VARPTR(BytesReply) )  
      If RetVal <> #CRYPT_OK THEN 
        sErr = "CryptPopData ERROR: "+Err2Str(RetVal)+" - "+ErrExStr(hCrypt) 
        ;function = -29 : EXIT function 
        ProcedureReturn -29
      ElseIf BytesReply > 0
        sReply = sReply + Left (sBuff, BytesReply) ; 
        last = Len(sReply) ; 
        PRINT #hDbg, "Rply:" + Str(BytesReply) + " Bytes: " + #CRLF$ + Left (sBuff, BytesReply) 
        *pByte = @sReply ; Check last line for SMTP code follwed by space
        If last > 5 And PeekC(*pByte + last-1) = 10 And PeekC(*pByte + last-2) = 13 ; CRLF 
          For k = 3 To last ; PRINT #hDbg, "CharNum=" + str(Last-k+1) + ", " + chr(@pByte[Last-k]) 
            If PeekC(*pByte + last-k) = 10 And PeekC(*pByte +last-k+4) = 32
              ;EXIT DO ; Space not a hyphen "-", Response complete 
              Break ;exit Repeat:ForEver
            EndIf 
            If k = last And PeekC(*pByte + last-k+3) = 32
              ;EXIT DO ; Space not a hyphen "-", Response complete 
              Break ;exit Repeat:ForEver
            EndIf
          Next
        EndIf   
      EndIf  
      ;loop
    ForEver ; PRINT #hDbg, BytesToHexPtr( STRPTR(sBuff), BytesReply )
  Wend 
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

oh thank you for that :)

So now I just need to know how PureBasic would call a function in a .dll.
Fred
Administrator
Administrator
Posts: 18152
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Fred »

Please take a look to the doc, it was a pain to write ;)

http://www.purebasic.com/documentation/

For the DLL:

http://www.purebasic.com/documentation/ ... index.html
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

Ah. I downloaded the .pdf manual and looked in there, then looked at all the installed examples but missed the online manual...
Dynamic linking is fine, but is Static linking possible?

So using the form:
Result = CallFunctionFast(*FunctionPointer [,Parameter1 [, Parameter2...]])

Code: Select all

      If OpenLibrary(0, "cl32.dll")
      
        *pCreateSession= GetFunction(0, "cryptCreateSession")
        If *pCreateSession
          RetVal = CallFunctionFast(*pCreateSession, *hSess, CRYPT_UNUSED, CRYPT_SESSION_SSL )
        EndIf
        
; other library calls


        CloseLibrary(0)

      EndIf
(posted here as a reference)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by srod »

If you have an import library for the dll then use Import for load time linking of the dll.
I may look like a mule, but I'm not a complete ass.
Mike Trader
User
User
Posts: 43
Joined: Tue Jul 10, 2007 8:09 pm

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by Mike Trader »

Ah great. Yes there is a .lib file for the project. I will need to include it with the source
So then I can use

Import "cl32.dll"

RetVal = cryptCreateSession( *hSess, CRYPT_UNUSED, CRYPT_SESSION_SSL )

.
.
.

This is all the remains to be translated:

Code: Select all

'¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION SMTPTLS( sSrvr AS STRING,_ 
                  sUser AS STRING,_ 
                  sPass AS STRING,_ 
                  sFrom AS STRING,_ 
                  sTo   AS STRING,_ 
                  sBody AS STRING,_  
                  sErr  AS STRING ) AS LONG 

  LOCAL RetVal, hSess, BytesReply, nRetLn AS LONG
  LOCAL sBuff, sReply, sEnc AS STRING 

    '- Initialize the Library
    RetVal = CryptInit() 
    IF RetVal <> %CRYPT_OK THEN sErr = "CryptInit ERROR: "+Err2Str(RetVal) : FUNCTION = -2 : EXIT FUNCTION         

    DO   
      '- Create the session
      RetVal = CryptCreateSession( VARPTR(hSess), %CRYPT_UNUSED, %CRYPT_SESSION_SSL ) 
      IF RetVal <> %CRYPT_OK THEN sErr = "CryptCreateSession ERROR: "+Err2Str(RetVal) : FUNCTION = -4 : EXIT DO    

      '- Add the server name "smtp.gmail.com" 
      RetVal = CryptSetAttributeString( hSess, %CRYPT_SESSINFO_SERVER_NAME, STRPTR(sSrvr), LEN(sSrvr) ) 
      IF RetVal <> %CRYPT_OK THEN sErr = "SERVER_NAME ERROR: "+Err2Str(RetVal)+" "+ErrExStr(hSess) : FUNCTION = -6 : EXIT DO    
                     
      '- Specify the Port
      RetVal = CryptSetAttribute( hSess, %CRYPT_SESSINFO_SERVER_PORT, %TCP_PORT ) 
      IF RetVal <> %CRYPT_OK THEN sErr = "SERVER_PORT ERROR: "+Err2Str(RetVal)+" "+ErrExStr(hSess) : FUNCTION = -8 : EXIT DO   

      '- Activate the session
      RetVal = CryptSetAttribute( hSess, %CRYPT_SESSINFO_ACTIVE, 1 ) 
      IF RetVal <> %CRYPT_OK THEN sErr = "SESSINFO_ACTIVE ERROR: "+Err2Str(RetVal)+" "+ErrExStr(hSess) : FUNCTION = -12 : EXIT DO  

      '- Discard initial response created by connecting   
      sBuff = NUL$(255)
      RetVal = CryptPopData( hSess, STRPTR(sBuff), LEN(sBuff), VARPTR(BytesReply) )  
      IF RetVal <> %CRYPT_OK THEN sErr = "CryptPopData1 ERROR: "+Err2Str(RetVal)+" "+ErrExStr(hSess) : FUNCTION = -27 : EXIT DO            
    

      '- MIME dialog
      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "EHLO " + $CRLF) '
      IF RetVal < 0 THEN FUNCTION = RetVal : EXIT DO   
      IF RetVal <> 250 THEN sErr = "EHLO Failed: "+sErr : FUNCTION = -31 : EXIT DO
                

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "AUTH LOGIN " + $CRLF) ' 
      IF RetVal <> 334 THEN sErr = "AUTH Failed: "+sErr : FUNCTION = -16 : EXIT DO

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, MimeEncode(sUser) + $CRLF) ' Username
      IF RetVal <> 334 THEN sErr = "user Failed: "+sErr : FUNCTION = -18 : EXIT DO 

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, MimeEncode(sPass) + $CRLF) ' Password
      IF RetVal <> 235 THEN sErr = "pass Failed: "+sErr : FUNCTION = -20 : EXIT DO  

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "MAIL FROM: <" + sFrom + ">" + $CRLF) ' Sender
      IF RetVal <> 250 THEN sErr = "MAIL FROM Failed: "+sErr : FUNCTION = -22 : EXIT DO  

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "RCPT TO: <" + sTo + ">" + $CRLF) ' Recipient
      IF RetVal <> 250 THEN sErr = "RCPT TO Failed: "+sErr : FUNCTION = -24 : EXIT DO   

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "DATA " + $CRLF) ' Body begins
      IF RetVal <> 354 THEN sErr = "DATA Failed: "+sErr : FUNCTION = -26 : EXIT DO   
    
      RetVal = TLSPushPop(hSess, sErr, sReply, 1, sBody   + $CRLF + "." + $CRLF) ' Body 
      IF RetVal <> 250 THEN sErr = "body Failed: "+sErr : FUNCTION = -28 : EXIT DO   
      sErr = "Email Sent OK" : FUNCTION = 1 ' 250 2.0.0 OK - Message sent 
  

      RetVal = TLSPushPop(hSess, sErr, sReply, 1, "QUIT " + $CRLF) ' Terminate MIME   
      IF RetVal < 0 THEN FUNCTION = RetVal : EXIT DO 
      IF RetVal <> 221 THEN sErr = "QUIT Failed: "+sErr : FUNCTION = -39 : EXIT DO   

      EXIT LOOP ' done
    LOOP ' 

    IF hSess THEN CALL CryptDestroySession(hSess) ' Close the session
    CALL CryptEnd() ' Close the Library

END FUNCTION 
 

'¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION PBMAIN()
         
  LOCAL RetVal AS LONG 
  LOCAL sBody, sErr AS STRING

hDbg = FREEFILE : OPEN $DEBUG_FILE FOR OUTPUT LOCK SHARED AS hDbg ' 

    sBody = ""
    sBody = sBody + "Date: "    + MailDate() + $CRLF
    sBody = sBody + "From: "    + $MailFrom  + $CRLF
    sBody = sBody + "To: "      + $MailTo    + $CRLF
    sBody = sBody + "Subject: " + "Gmail Test using TLS Encryption"  + $CRLF + $CRLF
    sBody = sBody + "Looks like this has worked!" 

    RetVal = SMTPTLS( $MailHost, $UserName, $Password, $MailFrom, $MailTo, sBody, sErr )       
    IF RetVal < 0 THEN PRINT #hDbg, "ERROR: "+sErr

CLOSE #hDbg
         
END FUNCTION 
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: SMTPS - sending emails via gmail using SSL/TLS

Post by srod »

Ah great. Yes there is a .lib file for the project. I will need to include it with the source
So then I can use

Import "cl32.dll"
No. You import the import library for the dll, not the dll itself. You need to use Import "cl32.lib". Within the Import/EndImport statements you then list the function declarations of those functions (or symbols) you wish to import (but look out for any function decoration / name mangling etc.) At compile time the import library will then be statically linked into your exe and then you simply include the dll with your completed application.
I may look like a mule, but I'm not a complete ass.
Post Reply