AppleScript - Python Mail Sender

14 Okt 2011 - 15:39

This script is for sending automatic Email messages without calling any user interface application. It is for text mail only, but mail may have attachments. Try the test script before diving into details: There are more variants of mail servers than this code may handle. (See note at end.)

Due to the variations among mail servers, feedback is extremely welcome in this case.

Zur deutschen Version

Installation

Download Mail_Sending_Library_AppleScript.zip and unzip the file.

The script library will work only if placed in a certain position on your hard drive.

Copy the folder “js_aux_scripts” to the folder “Application Support” in “Library” on the top level. (If such a folder exists: Copy the contents of the new one into the old one.)

The library has a handler that creates a “mail sender” using your login and address data. From it, you create a mail having a message body, a subject, a receiver and so on. This mail can be told to be sent out. It returns the message id used for that mail (the first message id if sent to a list of receivers).

Please note the page on Future Compatibility Issues for such libraries.

Brief Note on Technology

There are actually two scripts: An AppleScript “mail_sender.scptd” saved as a bundle and a Python script stored in it. The actual work is done by Python, the AppleScript is just wrapped around it to provide an AppleScript way of usage.

Testing the Script

Before diving into the details, please test the script first. There are too many variations of mail servers to be sure it works in every context.

When the library is installed, have a look at the testing script “testscript.scpt”. At the beginning, six variables are set. These are the data for logging into the mail server (SMTP) and data for an e-mail: address to send to, address sent from, real name of sender.

Please fill in real data for your test and run the script. Hopefully it works.

I tried the script with two company servers I have access to, with German t-online and with Google Mail. With these servers it worked.

Using the Script

The test script gives a first glance on how to use the library. But here is some more detailed description:

First, the script “mail_sender.scptd” must be loaded into some variable. This can be done with code like:

property app_supp : (path to application support) as text
property lib_path : "js_aux_scripts:mail_sender.scptd"
set e_mail_library to (load script file (app_supp & lib_path))

Once we have the library, an email sender can be created. The handler creating it takes five arguments: The address of your mail server (SMTP), the user name you need to log on, the password, your mail address and your name. The from_name is your real name as it should appear in the mail client of the receiver.

set e_mail_sender to new_mail_sender(server, username, my_password, from_box, from_name) of e_mail_library

This sender script has all the information about you. To create an email, some subject, a receiver and a message body are needed. Such a mail can be created from the sender:

set e_mail to new_mail(receiver, mail_subject, mail_text) of e_mail_sender

The mail address is US ASCII. the real name may have arbitrary characters.

Now, the mail is in the variable “e_mail”.

These is the minimum of information needed for a simple mail. If these properties are set, it makes sense to send out the mail:

tell e_mail to send_mail()

Multiple Recipients

There are two ways to send a mail to several people. First version: The mail_to is set to a string, containing several addresses, separated by commas. Example:

set mail_to of e_mail to "somebody@acme.tld, sbelse@bitbucket.tld, nobody@nowhere.tld"

(I am setting the property of an existing e_mail object here. Using such a string in the new_mail command does the same.)

To be honest: That is no feature I implemented. Mail servers just behave that way.

The second version: Use a list. Example:

set mail_to of e_mail to {"somebody@acme.tld", "sbelse@bitbucket.tld", "nobody@nowhere.tld"}

(Again, the list can be used in the new_mail command.)

The difference is: In the first version, one mail is sent out, having three recipients. In the second version, three mail variants are created with one recipient each.

Adding cc and bcc Receivers

Use

add_cc("my_friend@nowhere.com) of e_mail

to add a cc. For a bcc, use

add_bcc("my_friend@nowhere.com) of e_mail

Attaching files

Files are attached to the mail, using the “attach” command. Example:

set my_file to choose file
tell e_mail to attach(my_file)

The attach command may be called several times to attach several files.

Changing an Attachment Name

If you do not care about the name of the attachment, it will appear as the local file name on your hard disk. But optionally you can change it using “set_fileName”:

set_fileName("Sample Picture.png")

“set_fileName” will always change the name of the file attached most recently. Only the name in the mail is changed, the name on your disk remains unchanged.

Changing MIME Types

This is technical and in most cases it can be ignored. In an Email, the type of an attachment is marked by a MIME type header. This header does not depend on any file suffix.

If you do not touch it, the script tries to guess the MIME type from the file suffix. This works well in most cases. Still, there are special cases. Example:

set_mime_type("application/octet-stream")

will set that MIME type for the most recent attachment, even if it has a suffix like .pdf, .png and so on.

Setting the Default Encoding

For encoding the text, this script tries up to three ways: First, it tries to use US ASCII as required by RFC 2822. Second, it tries a default encoding, which is set to ISO latin 1 (= iso-8859-1) if you do not change anything. As a fall back, he script sends out mail as utf-8.

Note: If you do not care about encoding, the mail should be OK still. Setting a proper default encoding will just make the mail a little more efficient and the compatibility to very old mail clients (or strange ones) will be better.

If you live in a world where western latin script is used, the default is OK and do not care about it. But if most of your mail uses Latin script in Central European version (iso-8859-2), Baltic scripts (iso-8859-4), Cyrillic (iso-8859-5), Greek (iso-8859-7), Hebrew (iso-8859-8) or some other character set that has a standard encoding for email, you might want to change the behaviour.

set_encoding is used for that. In most cases, it can be used with a string for the encoding name, for example set_encoding("iso-8859-2"). In some cases, the name for the encoding in an email and in Python may be different. In such a case, use a list of two strings, first the mail encoding name, than the Python encoding name: set_encoding({"utf-8", "utf_8"}).

The Python Web site has a list of Python Encodings.

IANA has a list of Internet character sets. Use the ones marked as “preferred MIME name”.

Adding Headers to an Email

The handler “add_header(header_name, header_value)” may be used to add headers to an email. Each header has a name and a value.

Several headers for different purposes are defined for email. Check RFC 2822 as a starting point.

In scripting, one of the most important ones probably is “Reply-to”. It allows to set an address replies should be sent to. Example: add_header("Reply-to", "info@some.domain.tld") will add such a header to the mail. If a recipient of such a mail clicks the reply button, it will be addressed to the reply-to address.

Beside standard headers, there are “X-headers”. These are meant for own purposes. Still, there are some strong conventions about some of them. “X-priority” is understood by most mail clients. “X-mailer” should be used if you want to tell the recipient, which software produced the mail. But generally, you are free. Something like “X-file-under” could be used if you want to filter the scripted notifications automatically.

Header names should use ASCII characters and the hyphen only. They must not contain spaces. The value can be anything.

Setting the Message ID

Use this only if you know what you are doing!

Message IDs are a unique identifier for every mail sent out. This script uses a strategy close to the one used by Apple Mail. In rare cases in a scripting concept, it is useful if the script decides about the message id. If this is needed, set the property “message_id« of the mail to the one you need – including the < and > at beginning and end.

If mail is sent to a list of recipients, the copies get different message ids in this script. To use this with your own id string, use a placeholder “%s“ in it. It will be replaced by “-1”, “-2” etc. Hence “<abcd%s@j-schell.de>” will become “<abcd-1@j-schell.de>”, “<abcd-2@j-schell.de>”…

Problems to Connect to Server

I do expect some problems from the different ways SMTP servers require for logging on. Particularly encryption is an issue. Currently, the script tries a “starttsl” command. If that fails, it tries to logon without. More ways are not implemented. This should work with most servers but not with all. Feel free to contact me, if your server needs something different. I will not try to implement more ways without somebody who can test it.

Appendix

Example Google Mail

Works as of OS 10.6

For sending via Google Mail, use

smtp.gmail.com

as the server.

Your user name is your entire mail account, something like “your.name@googlemail.com”.

The password is the same you need to logon via Web.

The sender_box (or from_box in the sample code) is your mail address again.

International Domain Names

I am not so sure, many of them are around in an email context since the standard is for the domain name only but not for the mail box part of an address.

The script requires a domain name in US ASCII. If you have an international domain name (IDNA domain), convert it using something like:

on idna_dom(the_domain)
	set scrpt to "# -*- coding: utf-8 -*-
from encodings import idna
import sys
x = sys.argv[1].decode('utf_8')
y = idna.ToASCII(x)
print y"
	set cmd to "python -c "
	set scrpt to quoted form of scrpt
	set the_domain to quoted form of the_domain
	set r to (do shell script cmd & scrpt & " " & the_domain)
	return r
end idna_dom

Source Code

The source code for both the AppleScript and the Python script is on

Source Code mail_sender.scptd