To communicate with the IMAP server I will be using the imaplib as provided by the default python packages. Here is a basic example of login using this library

from imaplib import IMAP4

try:
    c = IMAP4('my_mail_server')
    c.login('my_username', 'my_password')
    c.logout()
except IMAP4.error, e:
    print 'An error occurred: %s' % e

All we need to do now is combine this with our Django backend code.

# import the User object
from django.contrib.auth.models import User

# import the IMAP library
from imaplib import IMAP4

# import time - this is used to create Django's internal username
import time

# Name my backend 'MyCustomBackend'
class MyCustomBackend:

    # Create an authentication method
    # This is called by the standard Django login procedure
    def authenticate(self, username=None, password=None):
        try:
            # Check if this user is valid on the mail server
            c = IMAP4('my_mail_server')
            c.login(username, password)
            c.logout()
        except:
            return None

        try:
            # Check if the user exists in Django's local database
            user = User.objects.get(email=username)
        except User.DoesNotExist:
            # Create a user in Django's local database
            user = User.objects.create_user(time.time(), username, 'passworddoesntmatter')

        return user

    # Required for your backend to work properly - unchanged in most scenarios
    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

In the above example I have assumed that your mail server is configured to use username@domain.com usernames. If not, you could modify as follows;

Replace

try:
    # Check if the user exists in Django's local database
    user = User.objects.get(email=username)
except User.DoesNotExist:
    # Create a user in Django's local database
    user = User.objects.create_user(time.time(), username, 'passworddoesntmatter')

With

# Check if the user exists, if not, create it.
user, created = User.objects.get_or_create(username=username)

You can also remove the import time as this was only used when creating a user when you needed something unique - the real username takes care of that.

Making Django use your new Authentication Backend.

In your settings.py add

AUTHENTICATION_BACKENDS = (
    'path.to.your.MyCustomBackend', 
    'django.contrib.auth.backends.ModelBackend', 
)

I think I have documented the code above well enough to understand without needing to go into too much detail.