Sending+an+HTML+email+with+optional+attachments

//by Richard Russell, April 2014, corrected August 2015//

In the article Sending an email with attachments the procedure **PROCsendmailattach** automatically sends an email using the SOCKLIB library. Listed below is a procedure which performs the same function except that you can send the body of the email as **HTML** instead of (or preferably as well as) **plain text**. The procedure might be called as follows: code format="bb4w" INSTALL @lib$+"SOCKLIB" SMTP$   = "smtp.gmail.com" From$   = "sender@somewhere" To$     = "recipient@elsewhere" Subject$ = "Test of sending attachments" ReplyTo$ = "reallyme@myaddress" Plain$  = "This is a test of sending an HTML email." HTML$   = "    " + \ \         "This is a test of sending an HTML email." + \     \          "  "      Attach$ =  """C:\Program Files\BBC BASIC for Windows\readme.txt""" PROCsendmailhtmlattach(SMTP$,From$,To$,"","",Subject$,ReplyTo$,Plain$,HTML$,Attach$) code The calling program should first check that the attached file(s) actually exist, because if not **PROCattach** will abort with an error and not terminate the SMTP transaction; this could leave the server 'in limbo'. **Note that if an attached file path contains spaces or punctuation characters you must enclose it in quotes**.

You should not assume that the receiving email client can necessarily render HTML, therefore ideally you should always include a **plain-text** message body as well as an **HTML** message body.

Here is **PROCsendmailhtmlattach**; like **PROCsendmail** it cannot be used if authentication is required so in practice that probably means that your ISP's SMTP server must be used: code format="bb4w" DEF PROCsendmailhtmlattach(smtp$,from$,rcpt$,cc$,bcc$,subject$,replyto$,plain$,html$,attach$) LOCAL D%, S%, skt%, comma%, reply$, file$ DIM D% LOCAL 31, S% LOCAL 15

SYS "GetLocalTime", S%     SYS "GetDateFormat", 0, 0, S%, "ddd, dd MMM yyyy ", D%, 18 SYS "GetTimeFormat", 0, 0, S%, "HH:mm:ss +0000", D%+17, 15 D%?31 = 13

PROC_initsockets skt% = FN_tcpconnect(smtp$,"mail") IF skt% <= 0 skt% = FN_tcpconnect(smtp$,"25") IF skt% <= 0 ERROR 100, "Failed to connect to mail server" IF FN_readlinesocket(skt%, 1000, reply$) WHILE FN_readlinesocket(skt%, 10, reply$) > 0 : ENDWHILE

PROCsend(skt%,"HELO "+FN_gethostname) PROCmail(skt%,"MAIL FROM: ",from$) IF rcpt$<>"" PROClist(skt%,rcpt$) IF cc$<>"" PROClist(skt%,cc$) IF bcc$<>"" PROClist(skt%,bcc$) PROCsend(skt%, "DATA")

IF FN_writelinesocket(skt%, "Date: "+$D%) IF FN_writelinesocket(skt%, "From: "+from$) IF FN_writelinesocket(skt%, "To: "+rcpt$) IF cc$<>"" IF FN_writelinesocket(skt%, "Cc: "+cc$) IF subject$<>"" IF FN_writelinesocket(skt%, "Subject: "+subject$) IF replyto$<>"" IF FN_writelinesocket(skt%, "Reply-To: "+replyto$) IF FN_writelinesocket(skt%, "MIME-Version: 1.0") IF attach$<>"" THEN IF FN_writelinesocket(skt%, "Content-Type: multipart/mixed; boundary=""BB4Wsep""") IF FN_writelinesocket(skt%, "") IF FN_writelinesocket(skt%, "--BB4Wsep") ENDIF IF plain$<>"" IF html$<>"" THEN IF FN_writelinesocket(skt%, "Content-Type: multipart/alternative; boundary=""BB4Wsep2""") IF FN_writelinesocket(skt%, "") IF FN_writelinesocket(skt%, "--BB4Wsep2") ENDIF IF plain$<>"" THEN IF FN_writelinesocket(skt%, "Content-Type: text/plain") IF FN_writelinesocket(skt%, "Content-Transfer-Encoding: 7bit") IF FN_writelinesocket(skt%, "") IF FN_writelinesocket(skt%, plain$) ENDIF IF plain$<>"" IF html$<>"" THEN IF FN_writelinesocket(skt%, "--BB4Wsep2") ENDIF IF html$<>"" THEN IF FN_writelinesocket(skt%, "Content-Type: text/html") IF FN_writelinesocket(skt%, "Content-Transfer-Encoding: 7bit") IF FN_writelinesocket(skt%, "") IF FN_writelinesocket(skt%, html$) ENDIF IF plain$<>"" IF html$<>"" THEN IF FN_writelinesocket(skt%, "--BB4Wsep2--") ENDIF IF attach$<>"" THEN REPEAT WHILE ASCattach$=32 attach$ = MID$(attach$,2) : ENDWHILE IF ASCattach$=34 THEN file$ = EVAL(attach$) comma% = INSTR(attach$, ",", LENfile$) ELSE comma% = INSTR(attach$, ",") IF comma% file$ = LEFT$(attach$, comma%-1) ELSE file$ = attach$ ENDIF PROCattach(skt%, file$) attach$ = MID$(attach$, comma%+1) UNTIL comma%=0 IF FN_writelinesocket(skt%, "--BB4Wsep--") ENDIF IF FN_writelinesocket(skt%, ".")

PROCsend(skt%,"QUIT")

PROC_exitsockets ENDPROC

DEF PROClist(skt%,list$) LOCAL comma% REPEAT WHILE ASClist$=32 list$=MID$(list$,2):ENDWHILE comma% = INSTR(list$,",") IF comma% THEN PROCmail(skt%,"RCPT TO: ",LEFT$(list$,comma%-1)) list$ = MID$(list$,comma%+1) ELSE PROCmail(skt%,"RCPT TO: ",list$) ENDIF UNTIL comma% = 0 ENDPROC

DEF PROCmail(skt%,cmd$,mail$) LOCAL I%,J% I% = INSTR(mail$,"<") J% = INSTR(mail$,">",I%) IF I% IF J% THEN PROCsend(skt%, cmd$+MID$(mail$,I%,J%-I%+1)) ELSE PROCsend(skt%, cmd$+"<"+mail$+">") ENDIF ENDPROC

DEF PROCsend(skt%,cmd$) LOCAL reply$ IF FN_writelinesocket(skt%,cmd$) < 0 THEN ERROR 100, "Send failed" ENDIF IF FN_readlinesocket(skt%, 200, reply$) WHILE FN_readlinesocket(skt%, 10, reply$) > 0 : ENDWHILE ENDPROC

DEF PROCattach(skt%,file$) LOCAL D%, F%, I%, L%, N%, A$, B$     B$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" F% = OPENIN(file$) IF F%=0 ERROR 100, "Failed to open attached file " + file$ REPEAT D% = INSTR(file$, "\") IF D%=0 D% = INSTR(file$, "/") IF D% file$ = MID$(file$, D%+1) UNTIL D%=0 IF FN_writelinesocket(skt%, "") IF FN_writelinesocket(skt%, "--BB4Wsep") IF FN_writelinesocket(skt%, "Content-Type: application/octet-stream") IF FN_writelinesocket(skt%, "Content-Disposition: attachment; filename="+file$) IF FN_writelinesocket(skt%, "Content-Transfer-Encoding: base64") IF FN_writelinesocket(skt%, "") L% = EXT#F% WHILE NOT EOF#F% N% = L% - PTR#F% D% = BGET#F% << 16 OR BGET#F% << 8 OR BGET#F% FOR I% = 1 TO 4 : A$ += MID$(B$,(D% >>> 18)+1,1) : D% = D% << 6 AND &FFFFFF : NEXT IF N%=1 RIGHT$(A$,2) = "==" ELSE IF N%=2 RIGHT$(A$) = "=" IF LENA$>=72 IF FN_writelinesocket(skt%,A$)=0 A$ = "" ENDWHILE IF A$<>"" IF FN_writelinesocket(skt%, A$) CLOSE #F% ENDPROC code