ESMTP, for all intents and purposes of this post, is essentially just SMTP but with a simple authentication step at the beginning (known as SMTP-AUTH) which is often required these days, to help ensure to your ISP that you really are the valid sender / who you say you are. After the authentication check is complete the communications continue using regular SMTP protocol.
Discussion here.
For a standard non-authenticated SMTP-only version see here, although this demo also supports regular SMTP.
This demo while small is fairly complete as it supports plain SMTP, ESMTP AUTH PLAIN, and ESMTP AUTH LOGIN (see %ESMTP_AUTH), although I haven't added CRAM-MD5 AUTH yet as my current mailserver doesnt support it, but it too is fairly easy to add detection & support for - see here for excellent info regarding AUTH. There is also DIGEST-MD5, although this doesn't seem very common compared to CRAM-MD5, AUTH PLAIN, and AUTH LOGIN.
IMPORTANT: Some email servers accept all three authentication methods available in this demo, whereas others may only accept one or two, so be sure to test your mail server with all three %ESMTP_AUTH values (0,1,2). The usual approach is to use SMTP (no auth) first, unless authentication is required, in which case you can determine which types of authentication are supported by the response the server sends back to you after you send it "EHLO". (Or alternatively, you can simply try each method until one succeeds, but listening to the servers header response is the faster & preferred approach).
Send to multiple email addresses (ie. BCC and CC emails):
To send to multiple email addresses (whether you want to BCC or CC) you simply send the "RCPT TO:" field over and over, once for each email address ... for which you should receive something like "250 recipient <[email protected]> ok" with each address.
Essentially, every email starts out as a BCC - the only difference between BCC and CC is that a CC message includes in its header who it was emailed to (so if you don't include the CC part it will remain a BCC, ie "blind"). Sample CC:
From: "From Me" <[email protected]>
To: "Person One" <[email protected]>
Cc: "Person Two" <[email protected]>, "Person Three" <[email protected]>
Discussion here.
For a standard non-authenticated SMTP-only version see here, although this demo also supports regular SMTP.
This demo while small is fairly complete as it supports plain SMTP, ESMTP AUTH PLAIN, and ESMTP AUTH LOGIN (see %ESMTP_AUTH), although I haven't added CRAM-MD5 AUTH yet as my current mailserver doesnt support it, but it too is fairly easy to add detection & support for - see here for excellent info regarding AUTH. There is also DIGEST-MD5, although this doesn't seem very common compared to CRAM-MD5, AUTH PLAIN, and AUTH LOGIN.
IMPORTANT: Some email servers accept all three authentication methods available in this demo, whereas others may only accept one or two, so be sure to test your mail server with all three %ESMTP_AUTH values (0,1,2). The usual approach is to use SMTP (no auth) first, unless authentication is required, in which case you can determine which types of authentication are supported by the response the server sends back to you after you send it "EHLO". (Or alternatively, you can simply try each method until one succeeds, but listening to the servers header response is the faster & preferred approach).
Code:
#COMPILE EXE '// Your mail server & mail account settings: $ESMTP_SERV = "mail.myisp.com" 'Mail server address $ESMTP_USER = "[email protected]" 'Mail account username $ESMTP_PASS = "myp4ssw0rd" 'Mail account password [I][COLOR=DimGray](that actually is my real password, but i faked my username)[/COLOR][/I] %ESMTP_PORT = 25 'ESMTP port (usually the same as your SMTP server. If you're not sure try 25, or 587) %ESMTP_AUTH = 0 '0=SMTP:No AUTH, 1=ESMTP:AUTH PLAIN, 2=ESMTP:AUTH LOGIN '\\ End of settings FUNCTION Base64enc (sText AS STRING, sOut AS STRING) AS LONG '// Base64 encode. Required for ESMTP (%ESMTP_AUTH=1or2) but not SMTP (%ESMTP_AUTH=0) #REGISTER NONE ! push ebp DIM ptr1 AS DWORD, ptr2 AS DWORD, dwLen AS DWORD ptr1 = STRPTR(sText): ptr2 = STRPTR(sOut): dwLen = LEN(sText) ! mov ecx, dwLen ! mov esi, ptr1 ! mov edi, ptr2 ! xor ebp,ebp ! call above_charset charset: ! db "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ! db "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z" ! db "0","1","2","3","4","5","6","7","8","9","+","/" above_charset: ! pop ebx ! push edi main_loop: ! dec ecx ! js end_base64 ! jnz not_one ! movzx edx,byte ptr [esi] ! bswap edx ! inc ecx ! inc ecx ! call encode_bytes ! mov ax, &h3D3D '== ! stosw ! jmp end_base64 not_one: ! dec ecx ! jnz not_two ! movzx edx,word ptr [esi] ! bswap edx ! xor ecx,ecx ! mov cl,3 ! call encode_bytes ! mov al, &h3D '= ! stosb ! jmp end_base64 not_two: ! dec ecx ! push ecx ! movzx edx,word ptr [esi] ! bswap edx ! mov dh,byte ptr [esi+2] ! xor ecx,ecx ! mov cl,4 ! call encode_bytes ! pop ecx ! add esi,3 ! jmp main_loop end_base64: ! pop ecx ! sub ecx,edi ! neg ecx ! pop ebp ! mov FUNCTION, ecx EXIT FUNCTION encode_bytes: ! cmp ebp,&h4C ! jnz no_crlf ! mov ax,&h0A0D ! stosw ! xor ebp,ebp no_crlf: ! xor eax,eax ! rol edx,6 ! mov al,dl ! and al,&b00111111 ! xlatb ! stosb ! inc ebp ! loop encode_bytes ! ret END FUNCTION FUNCTION SendEmail (sToName AS STRING, sToAddr AS STRING, sFromName AS STRING, sFromAddr AS STRING, sSubject AS STRING, sMessage AS STRING) AS LONG '// Returns 0 if successful, or errorcode LOCAL hTCP AS DWORD, sLocalHost AS STRING, sBuf AS STRING, sAuth AS STRING hTCP = FREEFILE TCP OPEN PORT %ESMTP_PORT AT $ESMTP_SERV AS hTCP IF ERR THEN FUNCTION = -1: GOTO ErrSMTP TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "220" THEN FUNCTION = -2: GOTO ErrSMTP HOST NAME TO sLocalHost IF sLocalHost = "" THEN sLocalHost = "email" '// ensure we have a name to send with the HELO/EHLO line '// AUTHENTICATION START 'SMTP: No AUTH #IF %ESMTP_AUTH = 0 TCP PRINT hTCP, "HELO " & sLocalHost TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -3: GOTO ErrSMTP 'ESMTP: AUTH PLAIN #ELSEIF %ESMTP_AUTH = 1 TCP PRINT hTCP, "EHLO " & sLocalHost '// EHLO (ESMTP) instead of HELO (SMTP) TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -4: GOTO ErrSMTP ? "AUTH types supported = " & sBuf sAuth = SPACE$(4096) Base64enc(CHR$(0) & $ESMTP_USER & CHR$(0) & $ESMTP_PASS, sAuth) TCP PRINT hTCP, "AUTH PLAIN " & RTRIM$(sAuth) TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "235" THEN FUNCTION = -5: GOTO ErrSMTP 'ESMTP: AUTH LOGIN #ELSEIF %ESMTP_AUTH = 2 TCP PRINT hTCP, "EHLO " & sLocalHost '// EHLO (ESMTP) instead of HELO (SMTP) TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -6: GOTO ErrSMTP ? "AUTH types supported = " & sBuf TCP PRINT hTCP, "AUTH LOGIN" TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "334" THEN FUNCTION = -7: GOTO ErrSMTP sAuth = SPACE$(4096): Base64enc($ESMTP_USER, sAuth) TCP PRINT hTCP, RTRIM$(sAuth) TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "334" THEN FUNCTION = -8: GOTO ErrSMTP sAuth = SPACE$(4096): Base64enc($ESMTP_PASS, sAuth) TCP PRINT hTCP, RTRIM$(sAuth) TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "235" THEN FUNCTION = -9: GOTO ErrSMTP #ELSE 'Invalid %ESMTP_AUTH value (must be 0, 1, or 2) #ENDIF '\\ END OF AUTHENTICATION 'Regular SMTP protocol from here on ... TCP PRINT hTCP, "MAIL FROM:" & sFromAddr TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -10: GOTO ErrSMTP TCP PRINT hTCP, "RCPT TO: " & sToAddr TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -11: GOTO ErrSMTP TCP PRINT hTCP, "DATA" TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "354" THEN FUNCTION = -12: GOTO ErrSMTP '// Beginning of email header TCP PRINT hTCP, "Date: " + DATE$ TCP PRINT hTCP, "From: " + CHR$(34) & sFromName & CHR$(34) & " <" & sFromAddr & ">" TCP PRINT hTCP, "To: " + CHR$(34) & sToName & CHR$(34) & " <" & sToAddr & ">" 'TCP PRINT hTCP, "Cc: " '// use this field if you want to change a BCC'd email into a CC'd email TCP PRINT hTCP, "Subject: " + sSubject TCP PRINT hTCP, "X-Mailer: PB ESMTP client demo" TCP PRINT hTCP, "" '// Beginning of email body TCP PRINT hTCP, sMessage TCP PRINT hTCP, "" '\\ End of the email. Resuming SMTP... TCP PRINT hTCP, "." TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "250" THEN FUNCTION = -13: GOTO ErrSMTP TCP PRINT hTCP, "QUIT" TCP RECV hTCP, 4096, sBuf IF LEFT$(sBuf, 3) <> "221" THEN FUNCTION = -14: GOTO ErrSMTP TCP CLOSE hTCP EXIT FUNCTION ErrSMTP: TCP CLOSE hTCP ? "ERROR. Last msg from server = " & sBuf END FUNCTION FUNCTION PBMAIN () AS LONG LOCAL lSent AS LONG, sToAddr AS STRING, sFromAddr AS STRING, sToName AS STRING, sFromName AS STRING, sSubject AS STRING, sMessage AS STRING '// Compose email (To & From Email Addresses plus Display Names, Subject, and Message Body) sToAddr = "[email protected]": sToName = "Alice Smith" sFromAddr = "[email protected]": sFromName = "Bob Jones" sSubject = "My subject" sMessage = "Email body line 1" & $CRLF & "Line 2" & $CRLF & "Line 3, ESMTP_AUTH is " & FORMAT$(%ESMTP_AUTH) '// Try to send the email lSent = SendEmail(sToName, sToAddr, sFromName, sFromAddr, sSubject, sMessage) IF lSent = 0 THEN ? "SUCCESS! MAIL SENT" ELSE ? "ERROR CODE = " & STR$(lSent) #IF %DEF(%PB_CC32) STDOUT "Done, press any key to continue...";: WAITKEY$ #ENDIF END FUNCTION
To send to multiple email addresses (whether you want to BCC or CC) you simply send the "RCPT TO:" field over and over, once for each email address ... for which you should receive something like "250 recipient <[email protected]> ok" with each address.
Essentially, every email starts out as a BCC - the only difference between BCC and CC is that a CC message includes in its header who it was emailed to (so if you don't include the CC part it will remain a BCC, ie "blind"). Sample CC:
From: "From Me" <[email protected]>
To: "Person One" <[email protected]>
Cc: "Person Two" <[email protected]>, "Person Three" <[email protected]>
Comment