(rfc smtp) - SMTP client

Library (rfc smtp)

This library provides simple SMTP client defined in RFC 5321.

The library provides high level APIs to use SMTP.

Following is the simple example to send an email.

(import (rnrs) (rfc client))

;; creates SMTP mail object
(define mail 
  (smtp:mail
   (smtp:from "Takashi Kato" "ktakashi@ymail.com")
   (smtp:subject "Subject")
   "Message"
   (smtp:cc "ktakashi@ymail.com")))

;; creates an SMTP connection
(define smtp-conn (make-smtp-connection "your.smtp.server.com" "587"))

;; connect to the server
(smtp-connect! smtp-conn) ;; returns SMTP connection

;; Authenticate if required.
(when (smtp-authentication-required? smtp-conn)
  ;; NOTE: only AUTH PLAIN is supported for now
  (cond ((memq 'PLAIN (smtp-connection-authentication-methods smtp-conn))
         (smtp-authenticate! smtp-conn (smtp-plain-authentication
                                        "username"
                                        "password")))
        (else (smtp-disconnect! smtp-conn)
              (error #f "authentication method not supported" 
                     (smtp-connection-authentication-methods smtp-conn)))))

;; Send it
(smtp-send! smtp-conn mail) ;; returns SMTP connection

;; Clean up
(smtp-disconnect! smtp-conn)

The followings describe how to create SMTP mail object with attachment(s) or inlined image.

;; Messae with attachment
(smtp:mail
 (smtp:from "Takashi Kato" "ktakashi@ymail.com")
 (smtp:subject "Message with attachment")
 "Message"
 (smtp:to "ktakashi@ymail.com")
 (smtp:attachment "application" "octet-stream" 
                  (get-file-content) ;; file content suitable for this
                  "file.odt"))

;; HTML message with inlined image.
(smtp:mail
 (smtp:from "Takashi Kato" "ktakashi@ymail.com")
 (smtp:subject "HTML message with inlined image")
 "<html><body><img src='cid:image' /></body></html>"
 (smtp:to "ktakashi@ymail.com")
 (smtp:attachment "image" "jpeg" 
                  ;; port can also be used
                  ;; NB: if you call smtp-mail->string twice in this case
                  ;;     then this may break. So make sure you use this
                  ;;     mail object once (includeing smtp-send!)
                  (open-file-input-port "image/file.jpg")
                  "image.jpg" 
                  ;; specifies content-disposition parameter
                  "inline"
                  ;; adding content-id of this attachment
                  '("content-id" "<image>"))
 ;; make this mail HTML
 (smtp:header "Content-Type" "text/html"))

Alternative message can be created like this:

;; Message with alternative
;; Content must not be specified otherwise raise an syntax error
(smtp:mail
 (smtp:from "Takashi Kato" "ktakashi@ymail.com")
 (smtp:subject "Message with alternative")
 (smtp:to "ktakashi@ymail.com")
 (smtp:alternative
  ("text" "plain" "Plain text message")
  ("text" "html" "<html><body>HTML message</body><html>"))
 )

High level APIs

Returns #t if the given obj is an SMTP connection object, Otherwise #f.

Creates an SMTP connection object.

If optional argument domain is specified, then the value is used for EHLO or HELO command parameter. Otherwise the result of machine-name (defined in SRFI 112) is used.

Returns a symbol list of possible authentication methods.

This procedure returns a proper value only after smtp-connect! is called.

Returns #t if the given SMTP connection requires authentication, otherwise #f.

This procedure returns a proper value only after smtp-connect! is called.

Establishes connection and return SMTP connection object.

initial-response-generator must be a procedure accepts 0 argument and must return 2 values, authentication method and initial response value (credential).

Authenticates the given smtp-connection. If the response status is 354 and next-step is specified, then the _next-step_is called with smtp-connection, status and response string. The procedure must return 2 values, next command and next-next procedure or #f. The smtp-authenticate! procedure stops when next-next procedure is #f or returning response is 235.

The following is a simple LOGIN next-step.

(define (smtp-login-authentication)
  (define (prompt next?)
    (lambda (conn status resp)
      (or (and (= status 334)
               ;; response is encoded to BASE 64 so decode it
               (display (base64-decode-string resp))
               (flush-output-port (current-output-port))
               ;; next command (either username or password)
               ;; must be encoded to BASE 64
               (values (base64-encode-string (get-line (current-input-port)))
                       (and next? (prompt #f))))
          (values #f #f))))
  (values (lambda () (values "LOGIN" #f)) (prompt #t)))

Sends the given smtp-mail and returns SMTP connection object.

The procedure internally calls smtp-mail->string. So if the smtp-mail object contains an attachment with input port, then the port position will be forwarded. Thus second call of the smtp-mail->string or smtp-send! doesn't create/send attachment message properly.

Disconnect the smtp-connection and returns SMTP connection.

The closed SMTP connection can be re-used.

Returns a thunk that can be used smtp-authenticate! procedure for PLAIN authentication.

Returns a thunk that can be used smtp-authenticate! procedure for LOGIN authentication.

The rest argument date is given, all of the values must be string, then each authentication prompt uses the given data as if it's typed by user. If there is no data or sufficient date, then input prompt will be shown and let user type the authentication information.

Auxiliary Syntax smtp:from
Auxiliary Syntax smtp:subject
Auxiliary Syntax smtp:to
Auxiliary Syntax smtp:cc
Auxiliary Syntax smtp:bcc
Auxiliary Syntax smtp:attachment
Auxiliary Syntax smtp:header

Constructs an SMTP mail object.

from must be one of the following forms:

(smtp:from email)

(smtp:from name email)

message-elements must be one of the following forms:

(smtp:subject subject)

(smtp:to email)

(smtp:to name email)

(smtp:cc email)

(smtp:cc name email)

(smtp:bcc email)

(smtp:bcc name email)

(smtp:attachment type subtype content)

(smtp:attachment type subtype content filename)

(smtp:attachment type subtype content filename disposition-parameter)

(smtp:attachment type subtype content filename disposition-parameter headers ...)

(smtp:alternative type subtype content)

(smtp:alternative type subtype content headers ...)

(smtp:header name value)

string

The order of the appearance does not matter, except string which will be the content of the creating SMTP mail. Except the smtp:subject and smtp:alternative, all elements can be appear multiple times.

Returns MIME string of given smtp-mail.

NOTE: the procedure consumes input port attachments if exists.

Middle level APIs

Creates an SMTP mail object.

Returns #t if the given obj is an SMTP mail object, otherwise #f.

creates an SMTP from object.

Returns #t if the given obj is an SMTP from object, otherwise #f.

Returns #t if the given obj is an SMTP recipient object, otherwise #f.

SMTP recipient objects are one of the following objects:

Creates SMTP to, SMTP cc and SMTP bcc objects respectively.

Returns #t if given obj is SMTP to, SMTP cc or SMTP bcc, respectively. Otherwise #f.

Creates a MIME object which represents SMTP attachment.

Together type and subtype represent MIME type. e.g. text/plaincontent can be string, bytevector, input-port.

Optional argument filename is specified, then content-dispositionheader will have filename parameter.

Optional argument disposition-parameter is specified, then content-disposition header will have specified parameter. Default values is attachment.

Rest argument headers is specified, then the created attachment has extra mime header. Each header must be a list which contains 2 elements, header name and value. The value part can also contain MIME parameters.

Creates a component of alternative message. The returning component is a mere MIME object.

type and subtype are the same as make-smtp-attachment.

Creates an alternative message. The returning message is a mere MIME object.

NOTE: the returning message should be added by smtp-mail-add-attachment!and not content argument of make-smtp-mail. To make mail construction easier, use smtp:mail macro.

Adds SMTP recipient recipient to smtp-mail and returns SMTP mail object.

Adds SMTP attachment attachment to smtp-mail and returns SMTP mail object.

Adds header to smtp-mail and returns SMTP mail object.

If there is the same header insense of string-ci=?, then the old one is overwritten.