Module SMTP and Attachments

Notices and updates
Locked
ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Module SMTP and Attachments

Post by ale870 »

Hello,

is there any way to send attachments using standard module?
Can I attach files simply encoding them using base64 and put the result inside the BODY? Or... ??

Thank you!
--

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

I only know , from long ago, that I just added the uuencoded file
directly in the message.. Its not seen as an attachment though..

The text must have a header and footer.. like ->

Code: Select all

begin 644 1
M1&]N="!E>'!E8W0@;64@=&\@<'5T(&UY('!A<W-W;W)D(&EN:&5R92`[+2D*
`
end
There is probably a X- value for the email header available for
attachments... have a look at the email RFC ;-)
-- (define? (Cornflakes))

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Thank you,
Now I'm working to study mail protocol (there is a special TAG in email settings to send attachments).
--

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

UPDATE... solved!
I modified original smtp module, and now it can be used to send attachments!
I'm completing (eliminating bad code and tests!), then I will upload it.
Lutz, how can I send you updated module (I still need some days)so you could test it and, if you want, you could put in the standard newLisp distribution?
--

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Hello,

I successfully modified original smtp.lsp module to send attachments too.

Since I don't know where I can post it, I will publish source code here:

Code: Select all

;; @module smtp.lsp 
;; @description Send mail using SMTP protocol
;; @version 2.0 - March 2008, Cormullion added AUTH PLAIN authentication 
;; @version 2.1 - changes for 10.0
;; @version 2.2 - (2009-07-16) Alessandro Manotti, Added multi-attachments support. Small bug-fixes.
;;
;; @author Lutz Mueller 2001, Cormullion 2008, Alessandro Manotti 2009
;;
;; <h2>Routines for sending mail</h2> 
;; This module implements routines to communicate with a SMTP mail server 
;; for sending email. To use this module include the following 'load' statement 
;; at the beginning of the program file: 
;; <pre> 
;; (load "/usr/share/newlisp/modules/smtp.lsp") 
;; </pre> 
;; To see debugging information: 
;; <pre>(set 'debug-flag true)</pre> 
;;
;; In order to use attachments, use the following flow (this is an example):
;; <pre>
;; (SMTP:clear-attachments)
;; (SMTP:add-attachment "/home/ale/temp/" "lisp.pdf" "This is a PDF file" "application/pdf")
;; (SMTP:add-attachment "/home/ale/temp/" "myimage.jpg" "My house!" "image/jpg")
;; (SMTP:send-mail "from_user@test.com" "to_user@test.com" "This is email subject" "This is the message-body!" "My server IP")
;; </pre>
;;
;; As you can see, you need to clear attachments list (that list is NOT automatically deleted, so you can
;; send the same attachments at different email addresses, by using (SMTP:send-mail) multiple times).
;; Then you can add your attachments, using the function (SMTP:add-attachment) with the following syntax:
;; <pre>
;; (SMTP:add-attachment file-path file-name attachment-name mime-type)
;; </pre>
;;
;; Then use (SMTP:send-mail) as usual.
;; NOTE: you can add as many attachments as you want.

(context 'SMTP) 

(set 'debug-flag nil) 

;; @syntax (SMTP:send-mail <str> <str> <str> <str> <str>i [<str> str-pass>]])
;; @param <str> The email address of the sender.
;; @param <str> The email address of the recipient.
;; @param <str> The subject line of the email.
;; @param <str> The message part of the email.
;; @param <str> The address of the SMTP server.
;; @param <str> Optional user name for authentication.
;; @param <str> Optional password for authentication.
;; @return On success 'true', on failure 'nil'.
;; In case the function fails returning 'nil', the function
;; 'SMTP:get-error-text' can be used to receive the error text.
;;
;; @example 
;; (SMTP:send-mail "jdoe@asite.com" "somebody@isp.com" "Greetings" 
;;   "How are you today? - john doe -" "smtp.asite.com" "jdoe" "secret") 

;; This logs in to the server, tries to authenticate using the username 'jdoe' and password 'secret' (if supplied), 
;; and sends an email with the format: 
;; <pre> 
;;  From:    jdoe@asite.com 
;;  To:      somebody@isp.com 
;;  Subject: Greetings 
;;  Message: How are you today? - John Doe - 
;; </pre> 
;;
;; ATTACHMENTS MANAGEMENT:
;; @syntax (SMTP:clear-attachments)
;; Clear the attachments list.
;;
;; @syntax (SMTP:add-attachment <str> <str> <str> <str>)
;; @param <str> Path of the file, terminating with "/".
;; @param <str> Name of the file to be attached.
;; @param <str> Attachment name (usually, it is the same name of the file-name).
;; @param <mime> Mime-type of the file.
;;

(context 'SMTP) 

(set 'debug-flag nil) 

; Files (filenames) that will be attached to the emails.
; This variable contains the following structure:
;   ( (attachment_1_info) (attachment_2_info) ... )
;   
;   Where:
;       (attachment_1_info) 
;           It is composed in this way:
;           (file-path file-name attachment-name mime-type)
;
;           file-path = [String] Path of the file, terminating with "/".
;                       Example (Linux): /home/ale/temp/
;                       Example (Win):   c:/ale/temp/
;
;           file-name = [String] Name of the file to be attached.
;
;           attachment-name = [String] Attachment name (usually, it is the same name of the file-name).
;
;           mime-type = [String] Mime-type of the file.
;                       Example:
;                       JPG image   -> "image/jpg"
;                       PNG image   -> "image/png"
;                       html file   -> "text/plain"
;
;                       More info about mime-types can be found at:
;                       http://www.iana.org/assignments/media-types/
;                       http://www.w3schools.com/media/media_mimeref.asp
;                       http://en.wikipedia.org/wiki/MIME
;
(setq attachmentsList '())

;; Key used to separate multi-parts.
(setq boundaryKey (string "==NextPart_H725_KHH93DBO77KK." (time-of-day)))

(define (send-mail mail-from mail-to mail-subject mail-body SMTP-server (user-name "") (password "")) 
    (and 
        (set 'from-hostname (nth 1 (parse mail-from "@"))) 
        (set 'socket (net-connect SMTP-server 25)) 
        (confirm-request "2") 
        (net-send-get-result (append "HELO " from-hostname) "2") 
        (unless (and (empty?  user-name) (empty? password)) 
           (mail-authorize user-name password) true) 
        (net-send-get-result (append "MAIL FROM: <" mail-from ">") "2") 
        (net-send-get-result (append "RCPT TO: <" mail-to ">") "2") 
        (net-send-get-result "DATA" "3") 
        (mail-send-header) 
        (mail-send-body) 
        (confirm-request "2") 
        (net-send-get-result "QUIT" "2") 
        (or (net-close socket) true))) 

(define (confirm-request conf)
    (net-receive socket recvbuff 256 "\r\n")
    (if debug-flag (println recvbuff) true)
    ; Empty out pipe. According to SMTP spec, last line has valid code.
    ; added for 1.8 for newLISP 9.2.0
    (while (< 0 (net-peek socket))
        (net-receive socket recvbuff 256 "\r\n")
        (if debug-flag (println recvbuff)))
    (starts-with recvbuff conf))
 
(define (net-send-get-result str conf) 
   (set 'send-str (append str "\r\n")) 
   (if debug-flag (println "sent: " send-str)) 
   (net-send socket send-str) 
   (if conf (confirm-request conf) true)) 

(define (mail-authorize user-name password) 
   (net-send-get-result 
       (append "AUTH PLAIN " 
               (base64-enc (append "\000" user-name "\000" password))) "235")) 

(define (mail-send-header) 
    (net-send-get-result (append "TO: " mail-to)) 
    (net-send-get-result (append "FROM: " mail-from)) 
    (net-send-get-result (append "SUBJECT: " mail-subject))     
)

(define (mail-send-body)
    (net-send-get-result (string {Content-Type: multipart/mixed; boundary="} boundaryKey {"}))
    (net-send-get-result "Mime-Version: 1.0") 
    (net-send-get-result (append "X-Mailer: newLISP v." (string (nth -2 (sys-info)))))
    (net-send-get-result "")        

    (net-send-get-result "")        
    (net-send-get-result (append "--" boundaryKey))
    (net-send-get-result "Content-Type: text/plain" )
    (net-send-get-result "Content-Transfer-Encoding: 7bit" )
    (net-send-get-result "")            
    (dolist (lne (parse mail-body "\r\n")) 
        (if (starts-with lne ".") 
            (net-send-get-result (append "." lne)) 
            (net-send-get-result lne))) 

    ;; If there are some attachments, put them in the email!
    
    (dolist (i attachmentsList)
        (prepare-attachment-for-sending (i 0) (i 1) (i 2) (i 3) )
    );dolist
    
    (net-send-get-result (append "--" boundaryKey "--"))
    (net-send-get-result ".")
);mail-send-body

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions to manage attachments.
;;
;; NOTE: after you send the email with attachments, such list is not cleared,
;; so you will be able to send another email using the same list!
;; Instead, to clear it, simply call (clear-attachments)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Clear attachments list.
;;
(define (clear-attachments)
    (setq attachmentsList '())
);clear-attachments

;; Add another attachment to be sent via email.
;;
(define (add-attachment argFilePath argFilename argAttachmentName argMimeType)
    (push (list argFilePath argFilename argAttachmentName argMimeType) attachmentsList -1)
);add-attachment

;; Link a single attachment to the email (prepare attachment to be sent).
;;
(define (prepare-attachment-for-sending argFilePath argFilename argAttachmentName argMimeType)
    (net-send-get-result "")
    (net-send-get-result (append "--" boundaryKey))
    (net-send-get-result (append {Content-Disposition: attachment; filename="} argFilename {"} ) )
    (net-send-get-result (append {Content-Type: } argMimeType {; name="} argAttachmentName {"} ) )
    (net-send-get-result "Content-Transfer-Encoding: base64" )
    (net-send-get-result "")
    (net-send socket (base64-enc (read-file (append argFilePath argFilename) )))
    (net-send-get-result "")
    (net-send-get-result "")
);prepare-attachment-for-sending

(define (get-error-text) 
    recvbuff) 

(context 'MAIN) 

;  test

; (set 'SMTP:debug-flag true) 

; (SMTP:send-mail 
;  "from@example.com" 
;  "to@example.com" 
;  "title" 
;  "body" 
;  "smtp.example.com" 
;  "user.name" 
;  "password")) 

; eof
--

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Thank you Alessandro, very nice addition!

Do you know the SMTP server, you have tested with, and the OS its running on? If I remember well, that will be shown in the response strings when you do: (set 'debug-flag true). At the moment I have no way to test this. Perhaps others can check this on as much mail servers as possible.

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Thank you.

About tests (successfully completed):

Client (newLisp): tested using Linux Mint 6.

Email client (received emails): Microsoft Outlook ("normal", not express edition) over Windows XP. Linux Evolution Mail+exchange plugin.

Server: Microsoft Exchange (I used it by using direct IP access: "10.100.2.207"). it is internal to the company where I work (on Windows server 2003).

Sorry, I didn't include debugging features, but if you want I can include them tomorrow :-)

I think you could include as "experimental module", and you can call it "smtp_attach.lsp" (in this way there is no risk to overwrite the official smtp module).

I successfully tested it sending multiple attachments: jpg and png images, and sending pdf files (mime-type: "application/pdf").

In the future, if everything works, I can include a facility to autoselect mime-type, based on attachment extension.

Please send me info on problems/bugs found. In such case, send me source of the received email, and any error found.

Thank you!
--

TedWalther
Posts: 608
Joined: Mon Feb 05, 2007 1:04 am
Location: Abbotsford, BC
Contact:

Post by TedWalther »

I've been meaning to write MIME module; alas, time pressure, time pressure. MIME is useful for so many things, could be used for the SMTP module, would be useful in the CGI module...

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Mime module? What do you mean exactly?
A module that supply mime-type based on file extension?
--

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Hello,

I updated SMTP version with attachments.
This new update includes:

1) debugging information
2) A new function to get a complete list of the files currently attached (SMTP: list-attachments)
3) In order to use this module via console, in a comfortable way, I added an online help. Every function now has, as first symbol, a string. It is the help for function usage. You can get more info from the console, typing: (SMTP:info?)

EDIT: This version has been tested even using newLisp on Windows XP :-).
So the compatibility list is the following:

SEND EMAIL:
Linux mint 6 - Ok
Windows XP - Ok

PROGRAMS TO READ EMAIL:
Outlook on Win XP - Ok
Evolution on Linux - Ok

EMAIL SERVER:
Microsoft Exchange


This is the full source code (version 2.2.1):

Code: Select all

;; @module smtp.lsp 
;; @description Send mail using SMTP protocol
;; @version 2.0   - March 2008, Cormullion added AUTH PLAIN authentication 
;; @version 2.1   - changes for 10.0
;; @version 2.2   - (2009-07-16) Alessandro Manotti, Added multi-attachments support. Small bug-fixes.
;; @version 2.2.1 - (2009-07-17) Alessandro Manotti.
;;      1) Added help online (SMTP:info?)
;;      2) Added debug support.
;;      3) Added new function: (SMTP:list-attachments)
;;
;; @author Lutz Mueller 2001, Cormullion 2008, Alessandro Manotti 2009
;;
;; <h2>Routines for sending mail</h2> 
;; This module implements routines to communicate with a SMTP mail server 
;; for sending email. To use this module include the following 'load' statement 
;; at the beginning of the program file: 
;; <pre> 
;; (load "/usr/share/newlisp/modules/smtp.lsp") 
;; </pre> 
;; To see debugging information: 
;; <pre>(set 'debug-flag true)</pre> 
;;
;; In order to use attachments, use the following flow (this is an example):
;; <pre>
;; (SMTP:clear-attachments)
;; (SMTP:add-attachment "/home/ale/temp/" "lisp.pdf" "This is a PDF file" "application/pdf")
;; (SMTP:add-attachment "/home/ale/temp/" "myimage.jpg" "My house!" "image/jpg")
;; (SMTP:send-mail "from_user@test.com" "to_user@test.com" "This is email subject" "This is the message-body!" "My server IP")
;; </pre>
;;
;; As you can see, you need to clear attachments list (that list is NOT automatically deleted, so you can
;; send the same attachments at different email addresses, by using (SMTP:send-mail) multiple times).
;; Then you can add your attachments, using the function (SMTP:add-attachment) with the following syntax:
;; <pre>
;; (SMTP:add-attachment file-path file-name attachment-name mime-type)
;; </pre>
;;
;; Then use (SMTP:send-mail) as usual.
;; NOTE: you can add as many attachments as you want.

(context 'SMTP) 

(set 'debug-flag nil) 

;; @syntax (SMTP:send-mail <str> <str> <str> <str> <str>i [<str> str-pass>]])
;; @param <str> The email address of the sender.
;; @param <str> The email address of the recipient.
;; @param <str> The subject line of the email.
;; @param <str> The message part of the email.
;; @param <str> The address of the SMTP server.
;; @param <str> Optional user name for authentication.
;; @param <str> Optional password for authentication.
;; @return On success 'true', on failure 'nil'.
;; In case the function fails returning 'nil', the function
;; 'SMTP:get-error-text' can be used to receive the error text.
;;
;; @example 
;; (SMTP:send-mail "jdoe@asite.com" "somebody@isp.com" "Greetings" 
;;   "How are you today? - john doe -" "smtp.asite.com" "jdoe" "secret") 

;; This logs in to the server, tries to authenticate using the username 'jdoe' and password 'secret' (if supplied), 
;; and sends an email with the format: 
;; <pre> 
;;  From:    jdoe@asite.com 
;;  To:      somebody@isp.com 
;;  Subject: Greetings 
;;  Message: How are you today? - John Doe - 
;; </pre> 
;;
;; ATTACHMENTS MANAGEMENT:
;; @syntax (SMTP:clear-attachments)
;; Clear the attachments list.
;;
;; @syntax (SMTP:list-attachments)
;; Show the list of the files currently attached; they will be sent using (SMTP:send-mail).
;;
;; @syntax (SMTP:add-attachment <str> <str> <str> <str>)
;; @param <str> Path of the file, terminating with "/".
;; @param <str> Name of the file to be attached.
;; @param <str> Attachment name (usually, it is the same name of the file-name).
;; @param <mime> Mime-type of the file.
;;

(context 'SMTP) 

;; This is a small utility to get functions help online via console!
;; USAGE:
;;  (SMTP:help <function>)
;;
;; EXAMPLE:
;,  (SMTP:info? SMTP:send-mail)
;;
(define (info? (argFn nil) )
  "This function!"
  
  (if debug-flag 
    (println "Function passed: " argFn))

  (if (= nil argFn)
    
    ; IF TRUE: HELP ONLINE ----------------------------------------------------
    ;
    (silent (println [text]
  Functions available:
  
  (SMTP:send-mail)
      Send an email (with attachments, if included).
  
  (SMTP:add-attachment)
      Add a new attachment. You can add multiple attachments recalling
      this function once for every attachment.
  
  (SMTP:clear-attachments)
      Clear all added attachments.
  
  (SMTP:list-attachments)
      Show a detailed list of the current files that will be attached to the email.
      
  Example how to get information using this function (SMTP:info?):
    > (SMTP:info? SMTP:send-mail)
    [/text]) )

    ; IF FALSE ----------------------------------------------------------------
    ;
    (silent (println (nth 1 argFn) ) )
  )
  
  (print "\n> ")
)

; Files (filenames) that will be attached to the emails.
; This variable contains the following structure:
;   ( (attachment_1_info) (attachment_2_info) ... )
;   
;   Where:
;       (attachment_1_info) 
;           It is composed in this way:
;           (file-path file-name attachment-name mime-type)
;
;           file-path = [String] Path of the file, terminating with "/".
;                       Example (Linux): /home/ale/temp/
;                       Example (Win):   c:/ale/temp/
;
;           file-name = [String] Name of the file to be attached.
;
;           attachment-name = [String] Attachment name (usually, it is the same name of the file-name).
;
;           mime-type = [String] Mime-type of the file.
;                       Example:
;                       JPG image   -> "image/jpg"
;                       PNG image   -> "image/png"
;                       html file   -> "text/plain"
;
;                       More info about mime-types can be found at:
;                       http://www.iana.org/assignments/media-types/
;                       http://www.w3schools.com/media/media_mimeref.asp
;                       http://en.wikipedia.org/wiki/MIME
;
(setq attachmentsList '())

;; Key used to separate multi-parts.
(setq boundaryKey (string "==NextPart_H725_KHH93DBO77KK." (time-of-day)))
(if debug-flag 
  (println "Auto-generated boundaryKey: " boundaryKey))


(define (send-mail mail-from mail-to mail-subject mail-body SMTP-server (user-name "") (password "")) 
  [text]
SYNTAX:
  (SMTP:send-mail <str> <str> <str> <str> <str>i [<str> str-pass>]])

PARAMETERS:
  <str> The email address of the sender.
  <str> The email address of the recipient.
  <str> The subject line of the email.
  <str> The message part of the email.
  <str> The address of the SMTP server.
  <str> Optional user name for authentication.
  <str> Optional password for authentication.

RETURN:
  On success 'true', on failure 'nil'.
  In case the function fails returning 'nil', the function
  'SMTP:get-error-text' can be used to receive the error text.

EXAMPLE:
  (SMTP:send-mail "jdoe@asite.com" "somebody@isp.com" "Greetings" "How are you today? - john doe -" "smtp.asite.com" "jdoe" "secret")
  [/text]
  
  (and 
      (set 'from-hostname (nth 1 (parse mail-from "@"))) 
      (set 'socket (net-connect SMTP-server 25)) 
      (confirm-request "2") 
      (net-send-get-result (append "HELO " from-hostname) "2") 
      (unless (and (empty?  user-name) (empty? password)) 
         (mail-authorize user-name password) true) 
      (net-send-get-result (append "MAIL FROM: <" mail-from ">") "2") 
      (net-send-get-result (append "RCPT TO: <" mail-to ">") "2") 
      (net-send-get-result "DATA" "3") 
      (mail-send-header) 
      (mail-send-body) 
      (confirm-request "2") 
      (net-send-get-result "QUIT" "2") 
      (or (net-close socket) true))
);send-mail

(define (confirm-request conf)
    "** Internal Function **"
    
    (net-receive socket 'recvbuff 256 "\r\n")
    
    ; Empty out pipe. According to SMTP spec, last line has valid code.
    ; added for 1.8 for newLISP 9.2.0
    (while (< 0 (net-peek socket))
        (net-receive socket recvbuff 256 "\r\n")
        (if debug-flag (println recvbuff)))
    (starts-with recvbuff conf))
 
(define (net-send-get-result str conf) 
  "** Internal Function **"

  (set 'send-str (append str "\r\n")) 
  (if debug-flag (println "sent: " send-str)) 
  (net-send socket send-str) 
  (if conf (confirm-request conf) true)) 

(define (mail-authorize user-name password) 
  "** Internal Function **"

  (net-send-get-result 
    (append "AUTH PLAIN " 
      (base64-enc (append "\000" user-name "\000" password))) "235")
) 

(define (mail-send-header) 
  "** Internal Function **"

  (net-send-get-result (append "TO: " mail-to)) 
  (net-send-get-result (append "FROM: " mail-from)) 
  (net-send-get-result (append "SUBJECT: " mail-subject))     
)

(define (mail-send-body)
    "** Internal Function **"

    (net-send-get-result (string {Content-Type: multipart/mixed; boundary="} boundaryKey {"}))
    (net-send-get-result "Mime-Version: 1.0") 
    (net-send-get-result (append "X-Mailer: newLISP v." (string (nth -2 (sys-info)))))
    (net-send-get-result "")        

    (net-send-get-result "")        
    (net-send-get-result (append "--" boundaryKey))
    (net-send-get-result "Content-Type: text/plain" )
    (net-send-get-result "Content-Transfer-Encoding: 7bit" )
    (net-send-get-result "")            
    (dolist (lne (parse mail-body "\r\n")) 
        (if (starts-with lne ".") 
            (net-send-get-result (append "." lne)) 
            (net-send-get-result lne))) 

    ;; If there are some attachments, put them in the email!
    
    (dolist (i attachmentsList)
        (if debug-flag (begin 
          (println "Preparing attachment...")
          (println "   argFilePath       : " (i 0))
          (println "   argFilename       : " (i 1))
          (println "   argAttachmentName : " (i 2))
          (println "   argMimeType       : " (i 3))
        ))

        (prepare-attachment-for-sending (i 0) (i 1) (i 2) (i 3) )
        
        (if debug-flag (println "   Done! -------------------------------"))

    );dolist
    
    (net-send-get-result (append "--" boundaryKey "--"))
    (net-send-get-result ".")
);mail-send-body

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions to manage attachments.
;;
;; NOTE: after you send the email with attachments, such list is not cleared,
;; so you will be able to send another email using the same list!
;; Instead, to clear it, simply call (clear-attachments)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Show current attachments list.
;;
(define (list-attachments)
  [text]
  SYNTAX:
    (list-attachments)
  
    Show a detailed list of the current files that will be attached to the email.
  [/text]

  (dolist (i attachmentsList)
    (println "File Path       : " (i 0))
    (println "File Name       : " (i 1))
    (println "Attachment Name : " (i 2))
    (println "Mime-Type       : " (i 3) "\n")
  )
  
  (silent (print "> "))
);list-attachments

;; Clear attachments list.
;;
(define (clear-attachments)
  [text]
  SYNTAX:
    (clear-attachments)
  
    Clear every previously added attachment.
  [/text]
  
  (setq attachmentsList '())
  (if debug-flag 
    (println "Attachments cleared!")
    (println "Current attachment list: " attachmentsList)
  )
);clear-attachments

;; Add another attachment to be sent via email.
;;
(define (add-attachment argFilePath argFilename argAttachmentName argMimeType)
  [text]
SYNTAX:  
  (SMTP:add-attachment <str> <str> <str> <str>)
  
PARAMETERS:
  <str> Path of the file, terminating with "/".
  <str> Name of the file to be attached.
  <str> Attachment name (usually, it is the same name of the file-name).
  <mime> Mime-type of the file.
  [/text]
  
    (push (list argFilePath argFilename argAttachmentName argMimeType) attachmentsList -1)
);add-attachment

;; Link a single attachment to the email (prepare attachment to be sent).
;;
(define (prepare-attachment-for-sending argFilePath argFilename argAttachmentName argMimeType)
    "** Internal Function **"

    (net-send-get-result "")
    (net-send-get-result (append "--" boundaryKey))
    (net-send-get-result (append {Content-Disposition: attachment; filename="} argFilename {"} ) )
    (net-send-get-result (append {Content-Type: } argMimeType {; name="} argAttachmentName {"} ) )
    (net-send-get-result "Content-Transfer-Encoding: base64" )
    (net-send-get-result "")
    (net-send socket (base64-enc (read-file (append argFilePath argFilename) )))
    (net-send-get-result "")
    (net-send-get-result "")
    
);prepare-attachment-for-sending

(define (get-error-text) 
  "** Internal Function **"

  recvbuff)

(context 'MAIN) 

;  test

; (set 'SMTP:debug-flag true) 

; (SMTP:send-mail 
;  "from@example.com" 
;  "to@example.com" 
;  "title" 
;  "body" 
;  "smtp.example.com" 
;  "user.name" 
;  "password")) 

; eof
--

TedWalther
Posts: 608
Joined: Mon Feb 05, 2007 1:04 am
Location: Abbotsford, BC
Contact:

Post by TedWalther »

ale870 wrote:Mime module? What do you mean exactly?
A module that supply mime-type based on file extension?
No, not at all. A module that could MIME-encode and MIME-decode.

So, if you have several files you want to turn into a MIME stream, it would try to auto-detect mime type of each chunk in the stream, but give you a simple way to override it.

And for MIME decode, it would take a stream of bytes and turn it into a bunch of streams, all nicely decoded, with the header data in a nice assoc list, and the body data in a string.

The base64 encoding/decoding would be folded into the MIME module, since that was where it originated, and it would also handle translating various encoding types to utf-8, etc.

So you could hand some data and header types to the MIME module encode function, and it will hand you one big string which is the MIME encoded encapsulation of that data. Decode would do the opposite.

With this functionality in place, you can quickly gin up a properly MIME encoded email message with attachments to send out, and you could trivially add support in the CGI module for a combination of POST data and file uploads, even multiple file uploads at the same time (this is what MIME type multipart/www-urlencoded is for)

And if someone sends you a properly MIME encoded message of any sort (email, web POST data, or stuff you haven't even dreamed of yet) the MIME decoder will properly split it up into various data chunks and preserve all the header information that DESCRIBES the particular chunk of data.

MIME is such a useful standard I'm surprised it isn't used in more places. Macintosh for instance, should have used MIME encoding instead of their "data and resource fork" idea.

Ted

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Sorry, but I cannot understand one point:
in order to use the correct mime-type, you need to know the "file-type" (pdf, jpg, etc...).
To do this, you have two ways:

1) Use file extension.
2) use the famous "magic number".

Can you better explain me your concept. Can you make me a small example?

Thank you!
--

xytroxon
Posts: 296
Joined: Tue Nov 06, 2007 3:59 pm
Contact:

Post by xytroxon »

You might want to make a module for the UUDeview library code...

http://fpx.de/fp/Software/UUDeview/
UUDeview is a program that helps you transmit and receive binary files over the Internet, using electronic mail or newsgroups The UUDeview package includes both an encoder and a decoder. The decoder automatically detects the type of encoding used, offering MIME's Base64 and BinHex as well as the popular uuencoding and the less frequently used xxencoding methods. Recently, support for the popular yEnc encoding was also added. The encoder runs the other way around and encodes a binary file for sending it by mail or news.
"Many computers can print only capital letters, so we shall not use lowercase letters."
-- Let's Talk Lisp (c) 1976

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

xytroxon wrote:You might want to make a module for the UUDeview library code...

http://fpx.de/fp/Software/UUDeview/
UUDeview is a program that helps you transmit and receive binary files over the Internet, using electronic mail or newsgroups The UUDeview package includes both an encoder and a decoder. The decoder automatically detects the type of encoding used, offering MIME's Base64 and BinHex as well as the popular uuencoding and the less frequently used xxencoding methods. Recently, support for the popular yEnc encoding was also added. The encoder runs the other way around and encodes a binary file for sending it by mail or news.
Module? Which one?
--

xytroxon
Posts: 296
Joined: Tue Nov 06, 2007 3:59 pm
Contact:

Post by xytroxon »

Yes, this legacy code from the early days of pre-internet file transfer is a mess, but it has a lot of functionality (yEnc) I still use with Windows/DOS command line Usenet postings ;)

Or do e-mail attachments not use these MIME encoding protocols???

-- xytroxon
"Many computers can print only capital letters, so we shall not use lowercase letters."
-- Let's Talk Lisp (c) 1976

TedWalther
Posts: 608
Joined: Mon Feb 05, 2007 1:04 am
Location: Abbotsford, BC
Contact:

Post by TedWalther »

xytroxon wrote:Yes, this legacy code from the early days of pre-internet file transfer is a mess, but it has a lot of functionality (yEnc) I still use with Windows/DOS command line Usenet postings ;)

Or do e-mail attachments not use these MIME encoding protocols???

-- xytroxon
*sigh* I get the feeling everyone else in this thread is using the word "MIME" to mean something completely other than what the RFC's specify.

uuencoding, like base64 encoding, is merely an encoding type. MIME can contain chunks of data of any type. As far as detecting the MIME type of data, that is a completely different subject, although a MIME module may well want to include utility functions for doing it, just as it should include uu and base64 encoding/decoding functions.

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

As far as I know is MIME nothng more than a Email header addon
for the use of Base64...

Probably MIME extended over the years with other formats but it was base64
originaly.. iirc..
-- (define? (Cornflakes))

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Not exactly: mime-types is a convention, standard description format, to define "which kind of file we are talking about". In this way a program can decide how to manage it.
It is a required information in order to exchange data from different operating systems (which they manage data in different ways).
--

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

Ha you read the RFC ..;-) thanks for clearing my dusty mind...;-)
-- (define? (Cornflakes))

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

:-)

http://en.wikipedia.org/wiki/MIME_type

(see RFC: it was born on 1993!!!)
But you are right: mime-type was used for the first time to exchange emails! (I discovered it now). Thank you for your hint!
--

xytroxon
Posts: 296
Joined: Tue Nov 06, 2007 3:59 pm
Contact:

Post by xytroxon »

ale870 wrote::-)

http://en.wikipedia.org/wiki/MIME_type

(see RFC: it was born on 1993!!!)
But you are right: mime-type was used for the first time to exchange emails! (I discovered it now). Thank you for your hint!
Suffering suffixes!!! ie er is not the same as ing!

I did a Google Search for: mime encoder
Did you mean: mime decoder Top 2 results shown
#
UUDeview Home Page
The decoder automatically detects the type of encoding used, offering MIME's Base64 and BinHex as well as the popular uuencoding and the less frequently ...
fpx.de/fp/Software/UUDeview/ - Cached - Similar
I should of done a Google Search for: mime encoding
MIME - Wikipedia, the free encyclopedia
MIME also specifies rules for encoding non-ASCII characters in e-mail message headers, such as "Subject:", allowing these header fields to contain ...
en.wikipedia.org/wiki/MIME - Cached - Similar
Python has an smtplib module:
http://docs.python.org/library/smtplib.html

And a higher level email module:
http://docs.python.org/library/email.html

I hope this helps ;)

-- xytroxon
"Many computers can print only capital letters, so we shall not use lowercase letters."
-- Let's Talk Lisp (c) 1976

Kirill
Posts: 90
Joined: Wed Oct 31, 2007 1:21 pm

Re: Module SMTP and Attachments

Post by Kirill »

Just came across MailGun. Which is, according to the docs, a programmable email platform. It allows sending and receiving messages with HTTP API. Receiving fully parsed message via HTTP sounds cool! And sending too, for that matter.

Haven't tested yet.

Locked