You need to replace the mail.settings with the proper parameters for your SMTP server. Set mail.settings.login = None if the SMTP server does not require authentication. If you don't want to use TLS, set mail.settings.tls = False

email logging

For debugging purposes you can set

mail.settings.server = 'logging'

and emails will not be sent but logged to the console instead.

Configuring email for Google App Engine

email from GAE

For sending emails from Google App Engine account:

mail.settings.server = 'gae'

At the time of writing web2py does not support attachments and encrypted emails on Google App Engine. Notice cron and scheduler do not work on GAE.

x509 and PGP Encryption

PGP

x509

It is possible to send x509 (SMIME) encrypted emails using the following settings:

It is possible to send PGP encrypted emails. First of all you need to install the python-pyme package. Then you can use GnuPG (GPG) to create the key-files for the sender (take the email-address from mail.settings.sender) and put the files pubring.gpg and secring.gpg in a directory (e.g. "/home/www-data/.gnupg").

Multiple attachments

Sending SMS messages

SMS

Sending SMS messages from a web2py application requires a third party service that can relay the messages to the receiver. Usually this is not a free service, but it differs from country to country. We have tried a few of these services with little success. Phone companies block emails originating from these services since they are eventually used as a source of spam.

A better way is to use the phone companies themselves to relay the SMS. Each phone company has an email address uniquely associated with every cell-phone number, so SMS messages can be sent as emails to the phone number.

SMSCODES is a dictionary that maps names of major phone companies to the email address postfix. The sms_email function takes a phone number (as a string) and the name of a phone company and returns the email address of the phone.

Using the template system to generate messages

emails

It is possible to use the template system to generate emails. For example, consider the database table

db.define_table('person', Field('name'))

where you want to send to every person in the database the following message, stored in a view file "message.html":

Dear {{=person.name}},
You have won the second prize, a set of steak knives.

It renders the view "message.html" with the variables defined in the dictionary "context", and it returns a string with the rendered email text. The context is a dictionary that contains variables that will be visible to the template file.

If the message starts with <html> and ends with </html>, the email will be an HTML email.

Note, if you want to include a link back to your website in an HTML email, you can use the URL function. However, by default, the URL function generates a relative URL, which will not work from an email. To generate an absolute URL, you need to specify the scheme and host arguments to the URL function. For example:

The same mechanism that is used to generate email text can also be used to generate SMS messages or any other type of message based on a template.

Sending messages using a background task

The operation of sending an email message can take up to several seconds because of the need to log into and communicate with a potentially remote SMTP server. To keep the user from having to wait for the send operation to complete, it is sometimes desirable to queue the email to be sent at a later time via a background task. As described in Chapter 4, this can be done by setting up a homemade task queue or using the web2py scheduler. Here we provide an example using a homemade task queue.

First, in a model file within our application, we set up a database model to store our email queue:

Finally, as described in Chapter 4, we need to run the mail_queue.py script as if it were inside a controller in our app:

python web2py.py -S app -M -R applications/app/private/mail_queue.py

where -S app tells web2py to run "mail_queue.py" as "app", -M tells web2py to execute models.

Here we assume that the mail object referenced in "mail_queue.py" is defined in a model file in our app and is therefore available in the "mail_queue.py" script because of the -M option. Also notice that it is important to commit any change as soon as possible in order not to lock the database to other concurrent processes.

As noted in Chapter 4, this type of background process should not be executed via cron (except perhaps for cron @reboot) because you need to be sure that no more than one instance is running at the same time.

Note, one drawback to sending email via a background process is that it makes it difficult to provide feedback to the user in case the email fails. If email is sent directly from the controller action, you can catch any errors and immediately return an error message to the user. With a background process, however, the email is sent asynchronously, after the controller action has already returned its response, so it becomes more complex to notify the user of a failure.

Reading and managing email boxes (Experimental)

The IMAP adapter is intended as an interface with email IMAP servers to perform simple queries in the web2py DAL query syntax, so email read, search and other related IMAP mail services (as those implemented by brands like Google(r), and Yahoo(r) can be managed from web2py applications.

It creates its table and field names "statically", meaning that the developer should leave the table and field definitions to the DAL instance by calling the adapter .define_tables() method. The tables are defined with the IMAP server mailbox list information.

Connection

For a single mail account, this is the code recommended to start IMAP support at the app's model

Note that <imapdb>.define_tables() returns a dictionary of strings mapping DAL tablenames to the server mailbox names with the structure {<tablename>: <server mailbox name>, ...}, so you can get the actual mailbox name in the IMAP server.

If you want to set you own tablename/mailbox configuration and skip the automatic name configuration, you can pass a custom dictionary to the adapter in this way:

imapdb.define_tables({"inbox":"MAILBOX", "trash":"SPAM"})

To handle the different native mailbox names for the user interface, the following attributes give access to the adapter auto mailbox mapped names (which native mailbox has what table name and vice versa):

Attribute

Type

Format

imapdb.mailboxes

dict

{<tablename>: <server native name>, ...}

imapdb.<table>.mailbox

string

"server native name"

The first can be useful to retrieve IMAP query sets by the native email service mailbox

# mailbox is a string containing the actual mailbox name
tablenames = dict([(v,k) for k,v in imapdb.mailboxes.items()])
myset = imapdb(imapdb[tablenames[mailbox]])

Fetching mail and updating flags

Here's a list of IMAP commands you could use in the controller. For the examples, it's assumed that your IMAP service has a mailbox named INBOX, which is the case for Gmail(r) accounts.

To count today's unseen messages smaller than 6000 octets from the inbox mailbox do

Say you want to have an app action show a mailbox message. First we retrieve the message (If your IMAP service supports it, fetch messages by uid field to avoid using old sequence references).

mymessage = imapdb(imapdb.INBOX.uid == <uid>).select().first()

Otherwise, you can use the message's id.

mymessage = imapdb.INBOX[<id>]

Note that using the message's id as reference is not recommended, because sequence numbers can change with mailbox maintenance operations as message deletions. If you still want to record references to messages (i.e. in another database's record field), the solution is to use the uid field as reference whenever supported, and retrieve each message with the recorded value.

Finally, add something like the following to show the message content in a view

As expected, we can take advantage of the SQLTABLE helper to build message lists in views

{{=SQLTABLE(myset.select(), linkto=URL(...))}}

And of course, it's possible to feed a form helper with the appropriate sequence id value

{{=SQLFORM(imapdb.INBOX, <message id>, fields=[...])}}

The current adapter supported fields available are the following:

Field

Type

Description

uid

string

answered

boolean

Flag

created

date

content

list:string

A list of text or html parts

to

string

cc

string

bcc

string

size

integer

the amount of octets of the message*

deleted

boolean

Flag

draft

boolean

Flag

flagged

boolean

Flag

sender

string

recent

boolean

Flag

seen

boolean

Flag

subject

string

mime

string

The mime header declaration

email

string

The complete RFC822 message**

attachments

list

Each non text decoded part as dictionary

encoding

string

The message's main detected charset

*At the application side it is measured as the length of the RFC822 message string

WARNING: As row id's are mapped to email sequence numbers, make sure your IMAP client web2py app does not delete messages during select or update actions, to prevent updating or deleting different messages.

Standard CRUD database operations are not supported. There's no way of defining custom fields or tables and make inserts with different data types because updating mailboxes with IMAP services is usually reduced to posting flag updates to the server. Still, it's possible to access those flag commands through the DAL IMAP interface

To mark last query messages as seen

seen = imapdb(q).update(seen=True)

Here we delete messages in the IMAP database that have mails from mr. Gumby