REBOL [
    Title: "Email attachments"
    Date: 20-Jul-1999
    File: %attach.r
    Author: "Sterling Newton"
    Purpose: "Send email with base64 encoded attachments"
    library: [
        level: 'advanced 
        platform: none 
        type: 'tool 
        domain: [email file-handling] 
        tested-under: none 
        support: none 
        license: none 
        see-also: none
    ]
]

line-break: func [data /num length] [
    if not num [length: 70]
    while [not tail? data] [
        data: insert skip data length "^/"
    ]
    data: head data
]

mail: func [
    {send a message with attached files}
    mesg [string!] {the message body}
    headers [object!] {headers object; usually made from system/standard/email}
    files [block!] {list of items to send; files will be loaded, 
other objects should be listed as [attachment-name object]}
    /local header make-boundary make-file-mime message boundary
][
    headers: make headers [MIME-Version: "1.0"]
    make-boundary: func [] [
        join "--__REBOL--" [system/version "--" now "--" 
            random to-integer (100 * (third now/time))
        ]
    ]
    make-file-mime: func [file /local data] [
        data: make string! 250
        insert data net-utils/export make object! [
            Content-Type: join {application/octet-stream; name="} [file {"}]
            Content-Transfer-Encoding: "base64"
            Content-Disposition: join {attachment; filename="} [file {"^/}]
        ]
        data
    ]
    message: make string! (length? mesg)
    header: headers
    if (length? files) > 0 [
         boundary: make-boundary
        header: make headers [
            content-type: join "multipart/mixed; boundary=" [
                {"} skip boundary 2 {"}
            ]
        ]
        insert mesg join boundary ["^/Content-type: text/plain^/^/"]
        append mesg "^/^/"
        foreach file files [
            file: reduce file
            append mesg join boundary [
                "^/" make-file-mime 
                either file? file [last parse file "/"] [first file]
            ]
            append mesg line-break 
            enbase either file? file [
                print ["reading file: " file] 
                read/binary file
            ] [
                either any-string? second file [
                    print ["attaching string object as: " first file] 
                    second file
                ] [
                    print ["attaching non-string object as: " first file] 
                    mold second file
                ]
            ]
        ]
        append mesg join boundary "--^/"
    ]
    send/header header/to mesg header
    reduce [header mesg]
]