32 bit SSL SMTP

Windows specific forum
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

32 bit SSL SMTP

Post by RichAlgeni »

This is a 32 bit SSL based SMTP process that I created to be able to send email via GMail. Credit goes to the fine people who wrote cryptlib.dll, Mike Trader from coastrd.com and the many good people who have helped me on the forum. Note that I renamed the dll's to a name a bit more descriptive than they were, and I reduced the header include file to it's bare minimum for SSL Email. You can find the entire project here:

http://www.rca2.com/dlls/Cryptlibdlls.zip

ssl_mail32.pbi

Code: Select all

;*****************************************************************************
;*                                                                           *
;*                        cryptlib External API Interface                    *
;*                       Copyright Peter Gutmann 1997-2008                   *
;*                                                                           *
;*                 Adapted For BASIC Nov 2009 - Coast Research               *
;*                 Adapted for PureBasic by Bart                             *
;*                                                                           *
;*****************************************************************************
;
;* Translated for PureBasic Nov 2009 from: http://www.coastrd.com/smtps/cryptlib/cryptlib_header-inc

#CRYPTLIB_VERSION    = 3330   ;  Not the same As 3.32

; cutdown version for SSL SMTP, 32 bit.

;  /****************************************************************************
;  *                                            General Constants               *
;  ****************************************************************************/

#CRYPT_MAX_KEYSIZE              =  256 ; /* The maximum user key size - 2048 bits */
#CRYPT_MAX_IVSIZE               =  32  ; /* The maximum IV size - 256 bits */
#CRYPT_MAX_PKCSIZE              =  512 ; The maximum public-key component size - 4096 bits, and maximum component
#CRYPT_MAX_PKCSIZE_ECC          =  72  ; size FOR ECCs - 576 bits (TO HANDLE the P521 curve) */
#CRYPT_MAX_HASHSIZE             =  32  ; /* The maximum hash size - 256 bits */
#CRYPT_MAX_TEXTSIZE             =  64  ; /* The maximum size of a text string (e.g.key owner name) */
#CRYPT_USE_DEFAULT              = -100 ; A magic value indicating that the default setting
#CRYPT_UNUSED                   = -101 ; /* A magic value for unused parameters */
#CRYPT_SESSION_SSL              =  03  ; /* SSL/TLS */
#CRYPT_SESSINFO_ACTIVE          = 6001 ; /* Whether session is active */
#CRYPT_SESSINFO_SERVER_NAME     = 6008 ; /* SERVER NAME */
#CRYPT_SESSINFO_SERVER_PORT     = 6009 ; /* SERVER PORT number */

;  /****************************************************************************
;  *                                           STATUS Codes                     *
;  ****************************************************************************/

; /* Errors in function calls */
#CRYPT_OK                       =   0  ; /* No error */
#CRYPT_ERROR_PARAM1             =  -1  ; /* Bad argument, parameter 1 */
#CRYPT_ERROR_PARAM2             =  -2  ; /* Bad argument, parameter 2 */
#CRYPT_ERROR_PARAM3             =  -3  ; /* Bad argument, parameter 3 */
#CRYPT_ERROR_PARAM4             =  -4  ; /* Bad argument, parameter 4 */
#CRYPT_ERROR_PARAM5             =  -5  ; /* Bad argument, parameter 5 */
#CRYPT_ERROR_PARAM6             =  -6  ; /* Bad argument, parameter 6 */
#CRYPT_ERROR_PARAM7             =  -7  ; /* Bad argument, parameter 7 */
;/* Errors due to insufficient resources */
#CRYPT_ERROR_MEMORY             = -10  ; /* Out of memory */
#CRYPT_ERROR_NOTINITED          = -11  ; /* Data has not been initialised */
#CRYPT_ERROR_INITED             = -12  ; /* Data has already been init;d */
#CRYPT_ERROR_NOSECURE           = -13  ; /* Opn.not avail.at requested sec.level */
#CRYPT_ERROR_RANDOM             = -14  ; /* No reliable random data available */
#CRYPT_ERROR_FAILED             = -15  ; /* Operation failed */
#CRYPT_ERROR_INTERNAL           = -16  ; /* Internal consistency check failed */
;/* Security violations */
#CRYPT_ERROR_NOTAVAIL           = -20  ; /* This type of opn.not available */
#CRYPT_ERROR_PERMISSION         = -21  ; /* No permiss.TO perform this operation */
#CRYPT_ERROR_WRONGKEY           = -22  ; /* Incorrect key used to decrypt data */
#CRYPT_ERROR_INCOMPLETE         = -23  ; /* Operation incomplete/still IN progress */
#CRYPT_ERROR_COMPLETE           = -24  ; /* Operation complete/can;t Continue */
#CRYPT_ERROR_TIMEOUT            = -25  ; /* Operation timed out before completion */
#CRYPT_ERROR_INVALID            = -26  ; /* Invalid/inconsistent information */
#CRYPT_ERROR_SIGNALLED          = -27  ; /* Resource destroyed by extnl.event */
;/* High-level function errors */
#CRYPT_ERROR_OVERFLOW           = -30  ; /* Resources/space exhausted */
#CRYPT_ERROR_UNDERFLOW          = -31  ; /* Not enough data available */
#CRYPT_ERROR_BADDATA            = -32  ; /* Bad/unrecognised data format */
#CRYPT_ERROR_SIGNATURE          = -33  ; /* Signature/integrity check failed */
;/* Data access function errors */
#CRYPT_ERROR_OPEN               = -40  ; /* Cannot OPEN object */
#CRYPT_ERROR_READ               = -41  ; /* Cannot READ item from object */
#CRYPT_ERROR_WRITE              = -42  ; /* Cannot WRITE item to object */
#CRYPT_ERROR_NOTFOUND           = -43  ; /* Requested item not found in object */
#CRYPT_ERROR_DUPLICATE          = -44  ; /* Item already present in object */
;/* Data enveloping errors */
#CRYPT_ENVELOPE_RESOURCE        = -50  ; /* Need resource to proceed */

;  /****************************************************************************
;  *                                        General Functions                   *
;  ****************************************************************************/

Global cryptLib.i               = OpenLibrary(#PB_Any, "cryptlib32.dll")

Global *cryptInit               = GetFunction(cryptLib, "cryptInit")
Global *cryptEnd                = GetFunction(cryptLib, "cryptEnd")
Global *cryptSetAttribute       = GetFunction(cryptLib, "cryptSetAttribute")
Global *cryptSetAttributeString = GetFunction(cryptLib, "cryptSetAttributeString")
Global *cryptCreateSession      = GetFunction(cryptLib, "cryptCreateSession")
Global *cryptDestroySession     = GetFunction(cryptLib, "cryptDestroySession")
Global *cryptCreateEnvelope     = GetFunction(cryptLib, "cryptCreateEnvelope")
Global *cryptDestroyEnvelope    = GetFunction(cryptLib, "cryptDestroyEnvelope")
Global *cryptPushData           = GetFunction(cryptLib, "cryptPushData")
Global *cryptFlushData          = GetFunction(cryptLib, "cryptFlushData")
Global *cryptPopData            = GetFunction(cryptLib, "cryptPopData")

Procedure.i cryptInit()
    ProcedureReturn CallFunctionFast(*cryptInit)
EndProcedure

Procedure.i cryptEnd()
    ProcedureReturn CallFunctionFast(*cryptEnd)
EndProcedure

Procedure.i cryptSetAttribute(hCrypt.i,CryptAttType.i, value.i)
   ProcedureReturn CallFunctionFast(*cryptSetAttribute, hCrypt.i,CryptAttType.i, value.i)
EndProcedure

Procedure.i cryptSetAttributeString(hCrypt.i, CryptAttType.i, pBuff.i, StrLen.i)
    ProcedureReturn CallFunctionFast(*cryptSetAttributeString, hCrypt.i, CryptAttType.i, pBuff.i, StrLen.i)
EndProcedure

;  /****************************************************************************
;  *                                        Envelope & Session Functions        *
;  ****************************************************************************/

Procedure.i cryptCreateSession(pSession.i, cryptUser.i, SessionType.i)
    ProcedureReturn CallFunctionFast(*cryptCreateSession, pSession.i, cryptUser.i, SessionType.i)
EndProcedure

Procedure.i cryptDestroySession(session.i)
    ProcedureReturn CallFunctionFast(*cryptDestroySession, session.i)
EndProcedure

Procedure.i cryptCreateEnvelope(penvelope.i, cryptUser.i, FormatType.i)
    ProcedureReturn CallFunctionFast(*cryptCreateEnvelope, penvelope.i, cryptUser.i, FormatType.i)
EndProcedure

Procedure.i cryptDestroyEnvelope(envelope.i)
    ProcedureReturn CallFunctionFast(*cryptDestroyEnvelope, envelope.i)
EndProcedure

Procedure.i cryptPushData(envelope.i, pBuff.i, StrLen.i,  pBytesCopied.i)
    ProcedureReturn CallFunctionFast(*cryptPushData, envelope.i, pBuff.i, StrLen.i,  pBytesCopied.i)
EndProcedure

Procedure.i cryptFlushData(envelope.i)
    ProcedureReturn CallFunctionFast(*cryptFlushData, envelope.i)
EndProcedure

Procedure.i cryptPopData(envelope.i, pBuff.i, StrLen.i, pBytesCopied.i)
    ProcedureReturn CallFunctionFast(*cryptPopData, envelope.i, pBuff.i, StrLen.i, pBytesCopied.i)
EndProcedure

;  /*****************************************************************************                                                                                                                 *
;  *                                          User Interface Functions          *
;  ****************************************************************************/

Procedure.s lookupError(errorCode.i)

    Select errorCode
    Case #CRYPT_OK
        ProcedureReturn  ""
    Case #CRYPT_ERROR_PARAM1
        ProcedureReturn  "Bad argument - parameter 1"
    Case #CRYPT_ERROR_PARAM2
        ProcedureReturn  "Bad argument - parameter 2"
    Case #CRYPT_ERROR_PARAM3
        ProcedureReturn  "Bad argument - parameter 3"
    Case #CRYPT_ERROR_PARAM4
        ProcedureReturn  "Bad argument - parameter 4"
    Case #CRYPT_ERROR_PARAM5
        ProcedureReturn  "Bad argument - parameter 5"
    Case #CRYPT_ERROR_PARAM6
        ProcedureReturn  "Bad argument - parameter 6"
    Case #CRYPT_ERROR_PARAM7
        ProcedureReturn  "Bad argument - parameter 7"
    Case #CRYPT_ERROR_MEMORY
        ProcedureReturn  "Out of memory"
    Case #CRYPT_ERROR_NOTINITED
        ProcedureReturn  "Data has not been initialized"
    Case #CRYPT_ERROR_INITED
        ProcedureReturn  "Data has already been initialized"
    Case #CRYPT_ERROR_NOSECURE
        ProcedureReturn  "Operation not available at requested security level"
    Case #CRYPT_ERROR_RANDOM
        ProcedureReturn  "No reliable random data available"
    Case #CRYPT_ERROR_FAILED
        ProcedureReturn  "Operation failed"
    Case #CRYPT_ERROR_INTERNAL
        ProcedureReturn  "Internal consistency check failed"
    Case #CRYPT_ERROR_NOTAVAIL
        ProcedureReturn  "This type of operation not available"
    Case #CRYPT_ERROR_PERMISSION
        ProcedureReturn  "No permission to perform this operation"
    Case #CRYPT_ERROR_WRONGKEY
        ProcedureReturn  "Incorrect key used to decrypt data"
    Case #CRYPT_ERROR_INCOMPLETE
        ProcedureReturn  "Operation incomplete/still in progress"
    Case #CRYPT_ERROR_COMPLETE
        ProcedureReturn  "Operation complete/can't continue"
    Case #CRYPT_ERROR_TIMEOUT
        ProcedureReturn  "Operation timed out before completion"
    Case #CRYPT_ERROR_INVALID
        ProcedureReturn  "Invalid/inconsistent information"
    Case #CRYPT_ERROR_SIGNALLED
        ProcedureReturn  "Resource destroyed by external event"
    Case #CRYPT_ERROR_OVERFLOW
        ProcedureReturn  "Resources/space exhausted"
    Case #CRYPT_ERROR_UNDERFLOW
        ProcedureReturn  "Not enough data available"
    Case #CRYPT_ERROR_BADDATA
        ProcedureReturn  "Bad/unrecognised data format"
    Case #CRYPT_ERROR_SIGNATURE
        ProcedureReturn  "Signature/integrity check failed"
    Case #CRYPT_ERROR_OPEN
        ProcedureReturn  "Cannot open object"
    Case #CRYPT_ERROR_READ
        ProcedureReturn  "Cannot read item from object"
    Case #CRYPT_ERROR_WRITE
        ProcedureReturn  "Cannot write item to object"
    Case #CRYPT_ERROR_NOTFOUND
        ProcedureReturn  "Requested item not found in object"
    Case #CRYPT_ERROR_DUPLICATE
        ProcedureReturn  "Item already present in object"
    Case #CRYPT_ENVELOPE_RESOURCE
        ProcedureReturn  "Need resource to proceed"
    Default
        ProcedureReturn  "Unknown error code: " + Str(errorCode)
    EndSelect

EndProcedure
email_ssl32.pb

Code: Select all

EnableExplicit

XIncludeFile "ssl_mail32.pbi"

#SMTP_RESPONSE_TIMEOUT = 5000 ; m/s

;****************************************************************************************
; receive data from the email server encrypted by ssl
;****************************************************************************************

Procedure.i sslRecvData(secureSession.i, *sslError, *returnData, *lenRtnData, buffSize.i)

    Protected retValue.i
    Protected totReturned = 0
    Protected totalMS.i   = 0

; get server response, wait as needed

    Repeat
        Delay(100)
        totalMS = totalMS + 100
        If totalMS > #SMTP_RESPONSE_TIMEOUT
            Break
        EndIf

        retValue = CryptPopData(secureSession, *returnData, buffSize, @totReturned)
        If retValue <> #CRYPT_OK
            PokeS(*sslError, "CryptPopData ERROR: " + lookupError(retValue))
            ProcedureReturn -999
        Else
            If totReturned > 0
                PokeI(*lenRtnData, totReturned)
                Break
            EndIf
        EndIf
    ForEver

    PrintN("Recd:")
    If totReturned > 0
        ConsoleColor(10,0)
        PrintN(PeekS(*returnData, totReturned))
        ConsoleColor(15,0)
    EndIf

    ProcedureReturn retValue

EndProcedure

;****************************************************************************************
; send data to the email server encrypted by ssl
;****************************************************************************************

Procedure.i sslSendData(secureSession.i, *sslError, *sendText, lenSendText)

    Protected retValue.i
    Protected bytesSent.i

; send data to email server

    retValue = CryptPushData(secureSession, *sendText, lenSendText, @bytesSent); used to copy data into an encrypted envelope
    If retValue <> #CRYPT_OK Or lenSendText <> bytesSent
        PokeS(*sslError, "CryptPushData ERROR " + lookupError(retValue) + ", lenSend = " + Str(lenSendText) + ", bytesSent = " + Str(bytesSent))
        ProcedureReturn -998
    EndIf

    retValue = CryptFlushData(secureSession); used to send data to remote machine
    If retValue <> #CRYPT_OK
        PokeS(*sslError, "CryptFlushData ERROR " + lookupError(retValue))
        ProcedureReturn -997
    EndIf

    PrintN("Sent:")
    ConsoleColor(14,0)
    PrintN(PeekS(*sendText, lenSendText))
    ConsoleColor(15,0)

    ProcedureReturn retValue

EndProcedure

;****************************************************************************************

Procedure.i SendPage(*mailHost, lenMailHost.i, mailPort.i, *userName, lenUserName, *password, lenPassword, *mailfrom, *mailTo, *emailBody, *rtnError)

    Protected retValue.i
    Protected cmdString.s
    Protected cmdNumber.i
    Protected lenghtTTS.i
    Protected sslSession.i
    Protected base64Size.i
    Protected base64Data.s
    Protected bytesRecvd.i
    Protected textToSend.s
    Protected serverReply.s
    Protected lenToEncode.i
    Protected replySize   = 255
    Protected mailfrom.s  = PeekS(*mailfrom)
    Protected mailTo.s    = PeekS(*mailTo)
    Protected emailBody.s = PeekS(*emailBody)

; create the ssl session

    retValue = CryptCreateSession(@sslSession, #CRYPT_UNUSED, #CRYPT_SESSION_SSL)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; add the server name "smtp.gmail.com"

    retValue = CryptSetAttributeString(sslSession, #CRYPT_SESSINFO_SERVER_NAME, *mailHost, lenMailHost)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; specify the Port, for SSL GMail, it's 465

    retValue = CryptSetAttribute(sslSession, #CRYPT_SESSINFO_SERVER_PORT, mailPort)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; activate the ssl session

    retValue = CryptSetAttribute(sslSession, #CRYPT_SESSINFO_ACTIVE, 1)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response created by connecting

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need 220, connection okay, begin enhanced smtp dialog

    If cmdNumber <> 220
        PokeS(*rtnError, "Invalid handshake received: " + cmdString)
        ProcedureReturn -996
    EndIf

; send EHLO to server

    textToSend = "EHLO" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from EHLO command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need 250, requested mail action okay, begin enhanced smtp dialog

    If cmdNumber <> 250
        PokeS(*rtnError, "EHLO Failed: " + cmdString)
        ProcedureReturn -995
    EndIf

; send auth login to server

    textToSend = "AUTH LOGIN" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from AUTH LOGIN command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need 334, ok to login, send username but encode the user name to base64 (mime) first

    If cmdNumber <> 334
        PokeS(*rtnError, "AUTH LOGIN Failed: " + cmdString)
        ProcedureReturn -994
    EndIf

; send the username to server

    base64Size  = lenUserName * 2
    If  base64Size < 64
        base64Size = 64
    EndIf

    base64Data = Space(base64Size + 1)
    Base64Encoder(*userName, lenUserName, @base64Data, base64Size)

    textToSend = base64Data + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from username command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need 334, username ok, send password but encode the password to base64 (mime) first

    If cmdNumber <> 334
        PokeS(*rtnError, "Username Failed: " + cmdString)
        ProcedureReturn -993
    EndIf

; send the password to server

    base64Size  = lenPassword * 2
    If  base64Size < 64
        base64Size = 64
    EndIf

    base64Data = Space(base64Size + 1)
    Base64Encoder(*password, lenPassword, @base64Data, base64Size)

    textToSend = base64Data + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from password command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need 235 = authentication ok or 250 = all ok, enter the from email address

    If cmdNumber <> 235 And cmdNumber <> 250
        PokeS(*rtnError, "Password Failed: " + cmdString)
        ProcedureReturn -992
    EndIf

; send the mail from address to server

    textToSend = "MAIL FROM: <" + mailfrom + ">" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from 'mail from' command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need a 250 here, sender ok, enter the receiving email address

    If cmdNumber <> 250
        PokeS(*rtnError, "MAIL FROM Failed: " + cmdString)
        ProcedureReturn -991
    EndIf

; send the receiving email address to server

    textToSend = "RCPT TO: <" + mailTo + ">" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from 'send to' command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; need a 250 or 251 here, ok to proceed, send the data command

    If cmdNumber <> 250 And cmdNumber <> 251
        PokeS(*rtnError, "RCPT TO Failed: " + cmdString)
        ProcedureReturn -990
    EndIf

; send the 'DATA' command

    textToSend = "DATA" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from 'DATA' command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; we should receive 354

    If cmdNumber <> 354
        PokeS(*rtnError, "DATA Failed: " + cmdString)
        ProcedureReturn -989
    EndIf

; send the mail itself, end with "." on a line by itself

    textToSend = emailBody + #CRLF$ + "." + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from 'end of data' command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; doesn't matter what we have received, we're going to quit anyway

    textToSend = "QUIT" + #CRLF$
    lenghtTTS  = Len(textToSend)
    retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
    If retValue <> #CRYPT_OK
        PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; receive response from 'quit' command

    serverReply = Space(replySize)
    retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
    If retValue = #CRYPT_OK
        cmdString = PeekS(@serverReply, 3)
        cmdNumber = Val(cmdString)
    Else
        PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
        ProcedureReturn retValue
    EndIf

; now end the ssl session

    If sslSession
        CryptDestroySession(sslSession)
    EndIf

    ProcedureReturn 0
EndProcedure

Define emailBody.s
Define errReturn.s = Space(255)
Define retValue.i, bytesRecvd.i

Define mailHost.s         = "smtp.gmail.com"               ; SMTP Host
Define lenMailHost.i      = Len(mailHost)
Define mailPort.i         = 465
Define mailFrom.s         = "my_email@gmail.com"
Define userName.s         = "my_email@gmail.com"           ; your gmail account
Define lenUserName.i      = Len(userName)
Define password.s         = "somepassword"                 ; your password
Define lenPassword.i      = Len(password)
Define mailTo.s           = "user@user.com"

emailBody = "From: "    + Mailfrom  + #CRLF$
emailBody + "To: "      + MailTo    + #CRLF$
emailBody + "Subject: " + "32 bit Gmail Test using SSL Encryption" + #CRLF$
emailBody + "Dear Sir, this email is brought to you courtesy of 32 bit SSL Encryption."

OpenConsole()
ConsoleColor(15,0)

; Initialize the crypt Library

Define initValue = CryptInit()
If initValue <> #CRYPT_OK
    errReturn = lookupError(initValue)
    PrintN(errReturn)
    End
EndIf

retValue = SendPage(@mailHost, lenMailHost, mailPort, @userName, lenUserName, @password, lenPassword, @mailfrom, @mailTo, @emailBody, @errReturn)
If retValue <> #CRYPT_OK
    PrintN(errReturn)
Else
    PrintN("EMail sent successfully!")
EndIf

CryptEnd() ; Close the Library

Input()

CloseConsole()
; IDE Options = PureBasic 4.61 (Windows - x86)
; ExecutableFormat = Console
; CursorPosition = 3
; Folding = -
; Executable = email_ssl32.exe
; CompileSourceDirectory
; Compiler = PureBasic 4.61 (Windows - x86)
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 794
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: 32 bit SSL SMTP

Post by Zebuddi123 »

Hi RichAlgeni just test 32bit version on windows 7 ultimate pb5.10beta1 works perfect :D I take it networking is your thing !

Thanks for sharing

Zebuddi. :D
malleo, caput, bang. Ego, comprehendunt in tempore
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

Thanks Zeb! You're welcome!
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

Just in case anyone was having a problem seeing the body of their email, RFC 2822 requires a blank line between the Subject field and the message body. So just add an extra #CRLF$ to the Subject line.
ricardo
Addict
Addict
Posts: 2402
Joined: Fri Apr 25, 2003 7:06 pm
Location: Argentina

Re: 32 bit SSL SMTP

Post by ricardo »

Hot to add a different email to answer ? reply-to:

Thanks in advance
ARGENTINA WORLD CHAMPION
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

Create a list of email addresses to send to:

Code: Select all

Global.s NewList mailToPeople()
Replace the 'rcpt to' block of code with this:

Code: Select all

    ForEach mailToPeople()
    
; send the receiving email address to server

        textToSend = "RCPT TO: <" + mailToPeople() + ">" + #CRLF$
        lenghtTTS  = Len(textToSend)
        retValue   = sslSendData(sslSession, *rtnError, @textToSend, lenghtTTS)
        If retValue <> #CRYPT_OK
            PokeS(*rtnError, "sslSendData ERROR: " + lookupError(retValue))
            ProcedureReturn retValue
        EndIf

; receive response from 'rcpt to' command

        serverReply = Space(replySize)
        retValue    = sslRecvData(sslSession, *rtnError, @serverReply, @bytesRecvd, replySize)
        If retValue = #CRYPT_OK
            cmdString = PeekS(@serverReply, 3)
            cmdNumber = Val(cmdString)
        Else
            PokeS(*rtnError, "sslRecvData ERROR: " + lookupError(retValue))
            ProcedureReturn retValue
        EndIf

; need a 250 or 251 here, ok to proceed, send the data command

        If cmdNumber <> 250 And cmdNumber <> 251
            PokeS(*rtnError, "RCPT TO Failed: " + cmdString)
            ProcedureReturn -990
        EndIf
    Next
DevilDog
Enthusiast
Enthusiast
Posts: 208
Joined: Thu Aug 04, 2005 9:32 pm
Location: Houston, Tx.

Re: 32 bit SSL SMTP

Post by DevilDog »

Hi RichAlgeni
I'm trying to use your email_ssl64 program to send email using Gmail.

My version of PB is 5.10 x64 and when I try to run it I get:

"The required compiler cannot be found: Purebasic 4.61 (Windows - x64)"

Any idea why it would do this?
When all is said and done, more is said than done.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

Yes, it's the way I saved it. While you have the program in focus in the IDE, click on 'Compiler', then 'Compiler Options'. You can un-check 'Use Compiler:', or just select the compiler you have on your system. What you are seeing now if the compiler I have on my system.

Rich
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

FYI, I keep two versions running on my development machine, just in case! 4.61 and 5.11.
DevilDog
Enthusiast
Enthusiast
Posts: 208
Joined: Thu Aug 04, 2005 9:32 pm
Location: Houston, Tx.

Re: 32 bit SSL SMTP

Post by DevilDog »

That's weird, I opened the compiler options, and the "Use Compiler:" checkbox is checked and to the right of that it shows my compiler version (5.10 x64) which I would take to mean that will use that compiler, yet when I unchecked that checkbox, it compiles!

Isn't that backwards? Is this an IDE bug?
When all is said and done, more is said than done.
User avatar
skywalk
Addict
Addict
Posts: 3996
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: 32 bit SSL SMTP

Post by skywalk »

Look at the hidden IDE settings located at the bottom of your source code using Notepad.exe.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
infratec
Always Here
Always Here
Posts: 6871
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: 32 bit SSL SMTP

Post by infratec »

Hi devildog,

use a normal editor open the .pb file and remove the last commented lines,
save it and try it again.

Bernd

Sh.. to slow :cry:
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

I'm not sure it's a bug, since it is the settings that I saved into the program. Just remember that you could hit this problem again, and it's a very simple fix. Once you un-check 'Use Compiler:', or select your own compiler, click on File, Save. That will take care of the issue for that program from now on.

Rich
fcb
User
User
Posts: 42
Joined: Fri Aug 31, 2012 10:12 pm

Re: 32 bit SSL SMTP

Post by fcb »

Hi - thanks for this great little program.

How do I specify a "From" name when I'm sending email?

At present I'm doing this:
mailFrom.s = "my_email@gmail.com"

And it's showing up in the recipients Gmail inbox as from "my_email", the reply path is correct.

What I would like to do is add something like:
mailFrom.s = "my_email@gmail.com"
mailFromName.s = "Company Inc."

So it would show up in receipients Gmail inbox as from "Company Inc.", the replyto address would still be "my_email@gmail.com"

many thanks,
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: 32 bit SSL SMTP

Post by RichAlgeni »

I think I understand what you're trying to do. In the example above, I used one variable, where you did it the better way, using two variables.

Try this instead:

Code: Select all

emailBody = "From: "  + mailFromName  + " <" + Mailfrom + ">"  + #CRLF$
Post Reply