PROCEDURE SendMailItem( strFrom, strTo, strSubject, strMsg, strBoundary, strAttach )
LOCAL lnCnt, laTO[1], lnGoodAddr, lnI, lcOutStr, lcMsg
EXTERNAL ARRAY arrAtch
If Not THIS.ReadWrite("RSET ")=250
THIS.GiveFeedback( [ERROR: Could not RSET to begin.],[(Server Returned "]+THIS.SrvRet+[")])
RETURN .f.
endif
If Not THIS.ReadWrite("MAIL FROM: " + alltrim(strFrom))=250
THIS.GiveFeedback( [ERROR: "MAIL FROM: "] + alltrim(strFrom) +[" FAILED],[(Server Returned "]+THIS.SrvRet+[")])
RETURN .f.
endif
lcMsg = strMsg
*!* if not empty(arrAtch) and type('arrAtch[1]')='C'
*!* lcMsg = lcMsg + crlf + crlf
*!* for lnI = 1 to ALEN(arrAtch,1)
*!* lcAtch = FileToStr( arrAtch[lnI] )
*!* lcAtch = THIS.UUEncode( arrAtch[lnI], lcAtch )
*!* endfor
*!*
*!* lcMsg = lcMsg + lcAtch
*!* endif
lnCnt = aLines(laTo, ChrTran(strTo,' ,;',chr(13)))
* once for each email address
lnGoodAddr = 0
for lnI = 1 to lnCnt
if not empty(laTo[lnI])
If THIS.ReadWrite("RCPT TO: " + alltrim(laTo[lnI])) = 250
lnGoodAddr = lnGoodAddr + 1
else
THIS.GiveFeedback( [ERROR: "RCPT TO: "] + alltrim(strFrom) +[" FAILED],[(Server Returned "]+THIS.SrvRet+[")])
*.. maybe only THIS one failed.
endif
endif
endfor
if lnGoodAddr=0
* Throw away this message (RSET=Reset)
If Not THIS.ReadWrite("RSET")=250
* Error, it should always reply "250 OK"
endif
THIS.GiveFeedback( [ERROR: No addresses were accepted by the server!])
RETURN .f.
endif
If Not THIS.ReadWrite("DATA")=354
STRTOFILE([--ERROR: "DATA" FAILED (Server Returned "]+THIS.SrvRet+[")]+crlf,'c:\temp\EmailLog.txt',.t.)
THIS.GiveFeedback( [ERROR: "DATA" FAILED],[(Server Returned "]+THIS.SrvRet+[")])
RETURN .f.
endif
* remove any inadvertant end-of-data marks:
lcMsg = StrTran(lcMsg, crlf+'.'+crlf, crlf+'. '+crlf)
* Build the MIME-compliant email, starting with headers
lcOutStr = "DATE: " + THIS.GetSmtpDateTime() +crlf;
+ "FROM: " + alltrim(strFrom) + CrLf ;
+ "TO: " + alltrim(strTo) + CrLf ;
+ "SUBJECT: " + alltrim(strSubject) + crlf
if not empty(strAttach)
lcOutStr = lcOutStr;
+ "MIME-Version: 1.0" + crlf ;
+ [Content-type: multipart/mixed;]+crlf;
+ chr(9)+ [boundary="]+strBoundary+["] + crlf
endif
* Add the Message to the email
lcOutStr = lcOutStr + crlf + lcMsg
* Finally, Add the contents.
if not empty(strAttach)
lcOutStr = lcOutStr + crlf + strAttach
endif
lcOutStr = lcOutStr + crlf + '--'+strBoundary + '--' + crlf
* THIS.GiveFeedback( [SENDING DATA...], [(Server Returned "]+THIS.SrvRet+[")])
do while not empty(lcOutStr)
INKEY(0.01)
if NOT THIS.Write( LEFT(lcOutStr,10000) )
STRTOFILE([--ERROR: MESSAGE DATA FAILED A (Server Returned "]+THIS.SrvRet+[")]+crlf,'c:\temp\EmailLog.txt',.t.)
THIS.GiveFeedback( [ERROR: MESSAGE DATA FAILED], [(Server Returned "]+THIS.SrvRet+[")])
RETURN .F.
endif
lcOutStr = SubStr(lcOutStr,10001)
enddo
* Give a brief pause for it all to go
inkey(0.5)
* Place end of data mark on end:
lcOutStr = crlf + "." && crlf always follows
lnStrt = SECONDS()
do while lnStrt+20 > seconds()
inkey(2)
If THIS.ReadWrite( crlf+crlf+'.' ) = 250
RETURN .T.
ENDIF
THIS.GiveFeedback( [TRYING AGAIN TO END DATA WITH <CRLF>.<CRLF>], ;
[(Server Returned "]+THIS.SrvRet+[")] )
enddo
STRTOFILE([--ERROR: MESSAGE DATA FAILED B (Server Returned "]+THIS.SrvRet+[")]+crlf,'c:\temp\EmailLog.txt',.t.)
THIS.GiveFeedback( [ERROR: MESSAGE DATA FAILED], [(Server Returned "]+THIS.SrvRet+[")])
RETURN .F.
ENDPROC
FUNCTION MimeEncode( strName, pcFileData )
*!* Content-Type: application/octet-stream; name="LEX.ico";
*!* x-mac-type="49434F00"; x-mac-creator="474B4F4E"
*!* Content-Transfer-Encoding: base64
*!* Content-Disposition: attachment; filename="LEX.ico"
*!*
*!* AAABAAEAICAQAAAAAADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAA
*!* --=====================_14459621==_
*!* Content-Type: application/octet-stream; name="ADrive.msk"
*!* Content-Transfer-Encoding: base64
*!* Content-Disposition: attachment; filename="ADrive.msk"
*!*
*!* Qk1mBAAAAAAAAHYAAAAoAAAALQAAABUAAAABAAQAAAAAAPgBAAAAAAAAAAAAABAAAAAQAAAAAAAA
LOCAL strFileName, lcOut, strFileData, lcEncoded, lcRecoded
*Get file name
strFileName = JustFName(strName)
if type('pcFileData')='C'
strFileData = pcFileData
else
strFileData = FileToStr(strName)
endif
lcOut = [Content-Type: application/octet-stream; name="]+strFileName+["]+crlf ;
+[Content-Transfer-Encoding: base64] +crlf;
+[Content-Disposition: attachment; filename="]+strFileName+["]+crlf;
+crlf
lcEncoded = THIS.EncodeStr64( strFileData )
lcReCoded = ''
do while not Empty(lcEncoded)
lcReCoded = lcReCoded + left(lcEncoded,76) + crlf
lcEncoded = Substr(lcEncoded,77)
enddo
RETURN lcOut + lcReCoded
ENDFUNC
Function EncodeStr64(sInput)
*!* ' Return radix64 encoding of string of binary values
*!* ' Does not insert CRLFs. Just returns one long string,
*!* ' so it's up to the user to add line breaks or other formatting.
*!* ' Version 4: Use Byte array and StrConv - much faster
* Converted From VB code at: [URL unfurl="true"]http://www.di-mgt.com.au/crypto.html#Base64[/URL]
PRIVATE aEncTab
* 1 2 3 1 1 1 1
* 01234567890123456789012345678901234567890123456789012345678901234567890
aEncTab = [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/]
LOCAL lcOut, nLen, iIndex, lcPart, i, j, nQuants, sLast
lcOut = ""
nLen = Len(sInput)
nQuants = int(len(sInput) / 3)
If (nQuants > 0) Then
*' Now start reading in 3 bytes at a time
For i = 0 To nQuants - 1
lcPart = ''
For j = 0 To 2
lcPart = lcPart + SubStr(sInput, (i*3) + j + 1, 1)
Next
lcPart = ThIS.EncodeQuantumB( lcPart )
lcOut = lcOut + lcPart
Next
*EncodeStr64 = StrConv(abOutput, vbUnicode)
* lcOut = StrConv(lcOut, 1) && singlebyte -> Dbl
* lcOut = StrConv(lcOut, 5) && DblBye -> Unicode
EndIf
*' Cope with odd bytes
*' (no real performance hit by using strings here)
do case
case nLen%3=0
sLast = ""
case nLen%3=1
sLast = SubStr(sInput, nLen, 1)+chr(0)+chr(0)
sLast = THIS.EncodeQuantumB(sLast)
* sLast = StrConv(b(, vbUnicode)
* sLast = StrConv(sLast,1)
* sLast = StrConv(sLast,5)
*' Replace last 2 with =
sLast = Left(sLast, 2) + "=="
case nLen%3=2
sLast = SubStr(sInput, nLen - 1, 1)+SubStr(sInput, nLen, 1)+chr(0)
sLast = THIS.EncodeQuantumB(sLast)
* sLast = StrConv(b(), vbUnicode)
* sLast = StrConv(sLast,1)
* sLast = StrConv(sLast,5)
*' Replace last with =
sLast = Left(sLast, 3) + "="
Endcase
RETURN lcOut+sLast
ENDFUNC
FUNCTION EncodeQuantumB( strIn )
*' Expects at least 4 bytes in b, i.e. Dim b(3) As Byte
LOCAL b0,b1,b2,b3
b0 = BitAnd( THIS.SHR2(asc(strIn)), 0x3F )
b1 = BitOr( THIS.SHL4( BitAnd( ASC(StrIn), 0x03 )), BitAnd(THIS.SHR4(ASC(SubStr(strIn,2))), 0x0F ) )
b2 = BitOr( THIS.SHL2( BitAnd( ASC(SubStr(StrIn,2)),0x0F )), BitAnd(THIS.SHR6(Asc(SubStr(strIn,3))), 0x03 ) )
b3 = BitAnd( Asc(Substr(strIn,3)), 0x3F )
RETURN Substr(aEncTab,b0+1,1)+Substr(aEncTab,b1+1,1)+Substr(aEncTab,b2+1,1)+Substr(aEncTab,b3+1,1)
EndFunc
*' Version 3: ShiftLeft and ShiftRight functions improved.
Function SHL2(bytValue)
*' Shift 8-bit value to left by 2 bits
*' i.e. VB equivalent of "bytValue << 2" in C
RETURN BitAnd(bytValue * 0x04, 0xFF)
EndFunc
Function SHL4(bytValue)
*' Shift 8-bit value to left by 4 bits
*' i.e. VB equivalent of "bytValue << 4" in C
RETURN BitAnd(bytValue * 0x10, 0xFF )
EndFunc
Function SHL6(bytValue )
*' Shift 8-bit value to left by 6 bits
*' i.e. VB equivalent of "bytValue << 6" in C
ReTURN BitAnd(bytValue * 0x40, 0xFF)
EndFunc
Function SHR2(bytValue )
*' Shift 8-bit value to right by 2 bits
*' i.e. VB equivalent of "bytValue >> 2" in C
RETURN INT( bytValue / 0x04 )
EndFunc
Function SHR4( bytValue )
*' Shift 8-bit value to right by 4 bits
*' i.e. VB equivalent of "bytValue >> 4" in C
RETURN INT( bytValue / 0x10 )
ENDFUNC
Function SHR6( bytValue )
*' Shift 8-bit value to right by 6 bits
*' i.e. VB equivalent of "bytValue >> 6" in C
RETURN INT( bytValue / 0x40 )
ENDFUNC