Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

sending attachments with SMTP? 3

Status
Not open for further replies.

poeijer

Programmer
May 29, 2002
69
0
0
NL
Can anyone explain to me how i can send attachments through SMTP?

i can send a normal email withouth an attachment. but i know u need to uunicode the attachment??

anyone has an example of that??

thanks in advance
 
Hi,

well i can send emails with smtp now + attachments.
2 bad i need to pay for it.................

do u know of a solution withouth payment?

greatings..

 
poeijer

do u know of a solution withouth payment?

I believe the author of the following is wgcs

Code:
FUNCTION SendSmtpEmail
LPARAMETERS strServ, strFrom, strTo, strSubj, strMsg
* strServ: The SMTP server to use. Can be in the following formats:
* xxx.xxx.xxx.xxx "xxx.xxx.xxx.xxx:port" "xxx.xxx.xxx.xxx port"
* ServerName "servername:port" "servername port"
* strFrom: The email address to provide as the "FROM" address
* strTo: The email address to send the email to.
* strSubj: Subject for the email
* strMsg: The Message to include as the body of the email.
#DEFINE crlf chr(13)+chr(10)
#DEFINE TIME_OUT 5

LOCAL Sock, llRet, lnI, laTO[1], lnCnt, lcServ, lnServPort
LOCAL lnTime, lcOutStr, Junk

Sock=create('mswinsock.winsock')
llRet = .F.

lnServPort = 25
lcServ = strServ
do case && Find Port
  case ':' $ lcServ
    lnAt = at(':',lcServ)
    lcServ = left( lcServ, lnAt-1 )
    lnServPort = val( Substr(lcServ, lnAt+1) )
    if lnServPort<=0
      lnServPort = 25
    endif
  case ' ' $ lcServ
    lnAt = at(' ',lcServ)
    lcServ = left( lcServ, lnAt-1 )
    lnServPort = val( Substr(lcServ, lnAt+1) )
    if lnServPort<=0
      lnServPort = 25
    endif
endcase

DO WHILE .T. && Control Loop
  sock.Connect(strServ,lnServPort)
  lnTime = seconds()
  do while sock.State <> 7
   ?&quot;Waiting to connect...&quot;
   inkey(0.1)
   if seconds() - lnTime > TIME_OUT
* ?&quot;Timed Out&quot;
     EXIT && Leave Control Loop
   endif
  enddo
* ?&quot;Connected.&quot;
  
  if not ReadWrite(sock,&quot;HELO &quot; + strServ, 220)
* ?&quot;Failed 1&quot;
     EXIT && Leave Control Loop
  endif
  
  If Not ReadWrite(sock,&quot;MAIL FROM: &quot; + strFrom, 250)
* ?&quot;Failed&quot;
     EXIT
  endif
  
  lnCnt = aLines(laTo, ChrTran(strTo,' ,;',chr(13)))
  * once for each email address
  for lnI = 1 to lnCnt
    If Not ReadWrite(sock,&quot;RCPT TO: &quot; + laTo[lnI], 250)
* ?&quot;Failed&quot;
      EXIT && Leave Control Loop
    endif
  endfor
  
  If Not ReadWrite(sock,&quot;DATA&quot;, 250)
* ?&quot;Failed&quot;
    EXIT && Leave Control Loop
  endif
  * tran(day(date()))+' '+tran(month(date()))+' '+tran(year(date()));
  * + ' ' +tran(hour(datetime()))+':'+tran(minute(datetime()))+':'+tran(sec(datetime())) +crlf
  
  lcOutStr = &quot;DATE: &quot; + TTOC( DateTime() ) +crlf;
           + &quot;FROM: &quot; + strFrom + CrLf ;
           + &quot;TO: &quot; + strTo + CrLf ;
           + &quot;SUBJECT: &quot; + strSubj ;
           + crlf ;
           + crlf ;
           + strMsg
  * remove any inadvertant end-of-data marks:
  lcOutStr = StrTran(lcOutStr, crlf+'.'+crlf, crlf+'. '+crlf)
  * Place end of data mark on end:
  lcOutStr = lcOutStr + crlf + &quot;.&quot;
  If Not ReadWrite(sock,lcOutStr, 354 )
* ?&quot;Failed&quot;
    EXIT && Leave Control Loop
  ENDIF
  
  If Not ReadWrite(sock,&quot;QUIT&quot;, 250)
* ?&quot;Failed&quot;
    EXIT && Leave Control Loop
  endif
  
  llRet = .T.
  EXIT && Leave Control Loop
ENDDO

* Do cleanup code.
Junk = repl(chr(0),1000)
sock.GetData(@Junk)
sock.close
sock = .null.
RETURN llRet
*--------------------------------------------------
Function ReadWrite( oSock, cMsgOut, iExpectedCode )
LOCAL cMsgIn, iCode, lnTime
  lnTime = seconds()
  do while oSock.BytesReceived = 0
* ?&quot;Waiting to Receive data...&quot;
   inkey(0.2)
   if seconds() - lnTime > TIME_OUT
* ?&quot;Timed Out&quot;
     return .F.
   endif
  enddo
  
  cMsgIn = repl(chr(0),1000)
  oSock.GetData(@cMsgIn)
  iCode = Val(Left(cMsgIn, 3))
  If iCode = iExpectedCode
    oSock.SendData( cMsgOut + CrLf )
  Else
* ?&quot;Failed; Code=&quot;+cMsgin
* ?&quot;Code=&quot;+tran(iCode)
    RETURN .F.
  Endif
RETURN .T.

Mike Gagnon

If you want to get the best response to a question, please check out FAQ184-2483 first.
 
Hi Mike,

yes that is the code i used before.
only there is no option in it for attachments as far as i could see..

i got that wwIPstuff to work now and i can easy send smtp with attachments. testing out if pop3 works as easy as well.

i might buy it then anyways.

thanks for your help!
 
Mike what about your CDO faq ?

I think it is faq184-1768

How to send e-mail Automating CDO
faq184-1768

*/*CDO.dll comes with Windows 2000 and XP

oMSG = CREATEOBJECT(&quot;cdo.message&quot;)
oMSG.To = &quot;me@nowhere.com&quot;
oMSG.From = &quot;me&quot;
oMSG.Subject = &quot;Hello Email&quot;
oMSG.TextBody = &quot;This is an easy way to create an email&quot;
oMSG.Send()

*/*Here are some other features of the CDO.Message:

oMSG = createobject(&quot;CDO.Message&quot;)
oMSG.To = &quot;me@nowhere.com&quot;
oMSG.From = &quot;me@nowhere.com&quot;
oMSG.Subject = &quot;Hello Email&quot;
oAtt=oMSG.AddAttachment('c:\myfile.txt')
oMSG.Send()

Foxy
 
John

I'm not sure that CDO handles SMTP servers, does it? Was it you that did some tests on that? I see no place in CDO to specify the server name. Mike Gagnon

If you want to get the best response to a question, please check out FAQ184-2483 first.
 
thread184-479076 Might help.. might not too..

FoxEgg
 
Indeed, CDO can be seen like MAPI.

it cant handle SMTP or POP connecting but uses the installed client on the PC to handle the mail routines.

 
CDO isn't garanteed to be on your customers' computers, though; It only installs with certain MS products (I don't remember which ones... Win2k Server is one..)

I haven't written any attachment handling in VFP yet, but Here's a page I just found that has it in VB:


I've converted the UUDecode to VFP, but haven't tested it at all, and I haven't started on the UUEncode at all:
Code:
Function UUDecode(strUUCodeData)
* From VB code at [URL unfurl="true"]http://www.vbip.com/winsock/winsock_uucode_04.asp[/URL]
LOCAL lnLines, laLines[1], lcOut, lnI, lnJ
LOCAL strDataLine, intSymbols, strTemp

*Remove first marker
If Left(strUUCodeData, 6) = &quot;begin &quot;
   strUUCodeData = Mid(strUUCodeData, _
                   InStr(1, strUUCodeData, vbLf) + 1)
EndIf

*Remove marker of the attachment's end
If Right(strUUCodeData, 5) = &quot;end&quot; + chr(13)+chr(10)
   strUUCodeData = Left(strUUCodeData, Len(strUUCodeData) - 10)
endif
strTemp = &quot;&quot;

*Break decoded data to the strings
*From now each member of the array vDataLines contains
*one line of the encoded data
lnLines = alines(laLines, strUUCodeData)
For lnI = 1 to lnLines
   *Decode data line by line
   strDataLine = laLines[lnI]
   
   *Extract the number of characters in the string
   *We can figure it out by means of the first string character
   intSymbols = Asc(Left(strDataLine, 1))
   
   *which we delete because of its uselessness
   strDataLine = Mid(strDataLine, 2, intSymbols)
   
   *Decode the string by 4 bytes portion. 
   *From each byte remove two oldest bits.
   *From remain 24 bits make 3 bytes
   For lnJ = 1 To Len(strDataLine) Step 4
      *1 byte
      strTemp = strTemp + Chr((Asc(SubStr(strDataLine, lnJ, 1)) ;
                - 32) * 4 + (Asc(SubStr(strDataLine, lnJ + 1, 1)) ;
                - 32) \ 16)
      *2 byte
      strTemp = strTemp + Chr((Asc(SubStr(strDataLine, lnJ + 1, 1)) ;
                % 16) * 16 + (Asc(SubStr(strDataLine, lnJ + 2, 1))  ;
                - 32) \ 4)
      *3 byte
      strTemp = strTemp + Chr((Asc(SubStr(strDataLine, lnJ + 2, 1)) ;
                % 4) * 64 + Asc(SubStr(strDataLine, lnJ + 3, 1)) - 32)
   ENDFOR
   *Write decoded string to the file
   lcOut = lcOut + strTemp
   
   *Clear the buffer in order to receive the next
   *line of the encoded data
   strTemp = &quot;&quot;
ENDFOR

RETURN lcOut
 
Here's the VFP-ified UUEncode routine. See for how to use this in sending an smtp email attachment.

(I tested this a little... it works in VFP without blowing up, but it seems awfully slow... there must be a way to speed it up. I know VFP8 adds functionality to STRCONV() to do most of this for you, but I don't know how much. )
Code:
Function UUEncode( strFilePath )

LOCAL strFileName, strFileData, i, j, lEncodedLines, ;
      strTempLine, lFileSize, strResult, strChunk

*Get file name
strFileName = JustFName(strFilePath)
strFileData = FileToStr(strFilePath)

*Insert first marker: &quot;begin 664 ...&quot;
strResult = &quot;begin 664 &quot; + strFileName + chr(10)

*Get file size
lFileSize = Len(strFileData)
lEncodedLines = int(lFileSize / 45) + 1

For i = 1 To lEncodedLines
    *Process file data by 45-bytes cnunks

    *reset line buffer
    strTempLine = &quot;&quot;
    
    If i = lEncodedLines Then
        *Last line of encoded data often is not
        *equal to 45
      strChunk = strFileData
      StrFileData = ''
    else
      strChunk    = LEFT(   strFileData, 45 )
      StrFileData = SubStr( strFileData, 46 )
    endif
    
    *Add first symbol to encoded string that informs
    *about quantity of symbols in encoded string.
    *More often &quot;M&quot; symbol is used.
    
    strTempLine = Chr(Len(strChunk) + 32)
    
    If i = lEncodedLines And (Len(strChunk) % 3<>0) Then
      *If the last line is processed and length of
      *source data is not a number divisible by 3, 
      *add one or two blankspace symbols
      strChunk = strChunk + Space( 3 -(Len(strChunk) % 3) )
    endif

    For j = 1 To Len(strChunk) Step 3
        *Break each 3 (8-bits) bytes to 4 (6-bits) bytes
        *
        *1 byte
        strTempLine = strTempLine +  ;
            Chr(Asc(SubStr(strChunk, j, 1)) / 4 + 32)
        *2 byte
        strTempLine = strTempLine +  ;
            Chr((Asc(SubStr(strChunk, j, 1)) % 4) * 16  ;
            + Asc(SubStr(strChunk, j + 1, 1)) / 16 + 32)
        *3 byte
        strTempLine = strTempLine +  ;
            Chr((Asc(SubStr(strChunk, j + 1, 1)) % 16) * 4  ;
            + Asc(SubStr(strChunk, j + 2, 1)) / 64 + 32)
        *4 byte
        strTempLine = strTempLine +  ;
            Chr(Asc(SubStr(strChunk, j + 2, 1)) % 64 + 32)
    EndFor
    
    *add encoded line to result buffer
    strResult = strResult + strTempLine + chr(10)
EndFor
*add the end marker
strResult = strResult + &quot;*&quot; + chr(10) + &quot;end&quot; + chr(10)
*asign return value
return strResult
 
Replace the inner loop with this, and you'll reduce the total time for encoding by about 1/3:

Code:
    For j = 1 To Len(strChunk) Step 3
        *Break each 3 (8-bits) bytes to 4 (6-bits) bytes
        ln1 = Asc(SubStr(strChunk, j, 1))
        ln2 = Asc(SubStr(strChunk, j + 1, 1))
        ln3 = Asc(SubStr(strChunk, j + 2, 1))
        *1 byte
        strTempLine = strTempLine +  Chr(ln1 / 4 + 32) ;
                                  +  Chr((ln1 % 4) * 16  + ln2 / 16 + 32) ;
                                  +  Chr((ln2 % 16) * 4  + ln3 / 64 + 32) ;
                                  +  Chr(ln3 % 64 + 32)
    EndFor
 
wgcs,

Did you ever get any further with this? Would be nice to have a mostly pure way todo email attachments directly from VFP and I am curious what the speed is like and what is the largest suitable file size for encoding or decoding.

Slighthaze = NULL
 
Thanks for the prod, Slighthaze...

Just for you, I finished it today.... Look for it in my Faq: faq184-3840
 
Nicely done! When I get a chance tonight I'll give this thing a go and see what gives.

Slighthaze = NULL
 
FYI: While I was at adjusting the SMTP sendMail code, I added sending HTML emails, too. Just start a message with <HTML> or <X-HTML> and it will be sent as content text/html

I tried, but couldn't make complete sense of multi-part/alternative messages, which allow you to send both plain text and HTML, so it can be read in any email viewer, (the examples I was reviewing didn't seem consitant...) If someone finds a good explanation of how to do these (that is, where to put the boundaries, what the format of a boundary string should be (i know it's mostly random, but how long, what characters, etc), where attachments fit into a multi-part/alternative email, etc, then I'd try again.

Also, suggestions on how to set the parameters so that it would be simple to send the multi part, too, while maintaining backward compatibility, etc. Or, it could just be a new, more powerful VFP send mail function, instead of cramming it all into the current one.
 
wgcs,

It is a nice program. You deserve another star

-- AirCon --
 
I forgot one thing, I need to adjust the TIMEOUT to higher than 10 in order to get it connected

Regards

-- AirCon --
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top