VirtualMailManager/EmailAddress.py
author Pascal Volk <neverseen@users.sourceforge.net>
Tue, 18 May 2010 07:00:21 +0000
branchv0.6.x
changeset 294 7d1bafc6fa30
parent 290 e2785e04f92e
child 316 31d8931dc535
permissions -rw-r--r--
VMM/Domain: removed functions ace2idna() and idn2ascii(). domainname.encode('idna')/domainname.decode('idna') works too.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     1
# -*- coding: UTF-8 -*-
162
0ac9ef587769 Updated copyright notices to include the year 2010.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 155
diff changeset
     2
# Copyright (c) 2008 - 2010, Pascal Volk
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     3
# See COPYING for distribution information.
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     4
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
     5
"""
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
     6
    VirtualMailManager.EmailAddress
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
     7
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
     8
    Virtual Mail Manager's EmailAddress class to handle e-mail addresses.
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
     9
"""
253
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    10
import re
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    11
254
8aecc83a0d32 VMM: moved functions ace2idna(), check_domainname(), idn2ascii()
Pascal Volk <neverseen@users.sourceforge.net>
parents: 253
diff changeset
    12
from VirtualMailManager.Domain import check_domainname
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    13
from VirtualMailManager.constants.ERROR import \
253
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    14
     DOMAIN_NO_NAME, INVALID_ADDRESS, LOCALPART_INVALID, LOCALPART_TOO_LONG
216
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    15
from VirtualMailManager.errors import EmailAddressError as EAErr
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    16
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    17
253
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    18
RE_LOCALPART = re.compile(r"[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]")
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    19
_ = lambda msg: msg
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    20
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    21
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    22
class EmailAddress(object):
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    23
    """Simple class for validated e-mail addresses."""
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    24
    __slots__ = ('_localpart', '_domainname')
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    25
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    26
    def __init__(self, address):
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    27
        """Creates a new instance from the string/unicode ``address``."""
213
1a9fee6b93bc VMM:/{Alias,EmailAddress,Relocated}: use assertions for argument checks.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 208
diff changeset
    28
        assert isinstance(address, basestring)
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    29
        self._localpart = None
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    30
        self._domainname = None
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    31
        self._chk_address(address)
116
949c5db6447a Fixed a logical mistake in EmailAddress.__ne__() (not used),
Pascal Volk <neverseen@users.sourceforge.net>
parents: 108
diff changeset
    32
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    33
    @property
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    34
    def localpart(self):
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    35
        """The local-part of the address *local-part@domain*"""
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    36
        return self._localpart
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    37
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    38
    @property
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    39
    def domainname(self):
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    40
        """The domain part of the address *local-part@domain*"""
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    41
        return self._domainname
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    42
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    43
    def __eq__(self, other):
116
949c5db6447a Fixed a logical mistake in EmailAddress.__ne__() (not used),
Pascal Volk <neverseen@users.sourceforge.net>
parents: 108
diff changeset
    44
        if isinstance(other, self.__class__):
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    45
            return self._localpart == other.localpart and \
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    46
                    self._domainname == other.domainname
116
949c5db6447a Fixed a logical mistake in EmailAddress.__ne__() (not used),
Pascal Volk <neverseen@users.sourceforge.net>
parents: 108
diff changeset
    47
        return NotImplemented
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    48
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    49
    def __ne__(self, other):
116
949c5db6447a Fixed a logical mistake in EmailAddress.__ne__() (not used),
Pascal Volk <neverseen@users.sourceforge.net>
parents: 108
diff changeset
    50
        if isinstance(other, self.__class__):
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    51
            return self._localpart != other.localpart or \
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    52
                    self._domainname != other.domainname
116
949c5db6447a Fixed a logical mistake in EmailAddress.__ne__() (not used),
Pascal Volk <neverseen@users.sourceforge.net>
parents: 108
diff changeset
    53
        return NotImplemented
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    54
218
84094c7fa28b VMM/EmailAddress: implemented EmailAddress.__hash__().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 216
diff changeset
    55
    def __hash__(self):
84094c7fa28b VMM/EmailAddress: implemented EmailAddress.__hash__().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 216
diff changeset
    56
        return hash((self._localpart.lower(), self._domainname.lower()))
84094c7fa28b VMM/EmailAddress: implemented EmailAddress.__hash__().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 216
diff changeset
    57
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    58
    def __repr__(self):
195
05dd49fc3ea1 VMM/EmailAddress: reworked class EmailAddress again.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 194
diff changeset
    59
        return "EmailAddress('%s@%s')" % (self._localpart, self._domainname)
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    60
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    61
    def __str__(self):
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    62
        return '%s@%s' % (self._localpart, self._domainname)
76
14c0a092d7d2 * 'VirtualMailManager/EmailAddress.py'
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    63
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    64
    def _chk_address(self, address):
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    65
        """Checks if the string ``address`` could be used for an e-mail
215
33f727efa7c4 PEP-8-ified the work of the last days.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 213
diff changeset
    66
        address.  If so, it will assign the corresponding values to the
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    67
        attributes `_localpart` and `_domainname`."""
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    68
        parts = address.split('@')
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    69
        p_len = len(parts)
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    70
        if p_len < 2:
216
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    71
            raise EAErr(_(u"Missing the '@' sign in address %r") % address,
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    72
                        INVALID_ADDRESS)
193
a259bdeaab5c VMM/EmailAddress: rework EmailAddress class.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 185
diff changeset
    73
        elif p_len > 2:
216
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    74
            raise EAErr(_(u"Too many '@' signs in address %r") % address,
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    75
                        INVALID_ADDRESS)
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    76
        if not parts[0]:
216
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    77
            raise EAErr(_(u'Missing local-part in address %r') % address,
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    78
                        LOCALPART_INVALID)
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    79
        if not parts[1]:
216
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    80
            raise EAErr(_(u'Missing domain name in address %r') % address,
0c8c053b451c Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 215
diff changeset
    81
                        DOMAIN_NO_NAME)
199
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    82
        self._localpart = check_localpart(parts[0])
0684790fff7c VMM: renamed function chk_domainname() -> check_domainname().
Pascal Volk <neverseen@users.sourceforge.net>
parents: 195
diff changeset
    83
        self._domainname = check_domainname(parts[1])
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    84
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
    85
253
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    86
def check_localpart(localpart):
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    87
    """Returns the validated local-part `localpart`.
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    88
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    89
    Throws a `EmailAddressError` if the local-part is too long or contains
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    90
    invalid characters.
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    91
    """
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    92
    if len(localpart) > 64:
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    93
        raise EAErr(_(u"The local-part '%s' is too long") % localpart,
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    94
                    LOCALPART_TOO_LONG)
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    95
    invalid_chars = set(RE_LOCALPART.findall(localpart))
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    96
    if invalid_chars:
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
    97
        i_chars = u''.join((u'"%s" ' % c for c in invalid_chars))
290
e2785e04f92e VMM/…: re-indented long queries and error messages.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 254
diff changeset
    98
        raise EAErr(_(u"The local-part '%(l_part)s' contains invalid "
e2785e04f92e VMM/…: re-indented long queries and error messages.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 254
diff changeset
    99
                      u"characters: %(i_chars)s") % {'l_part': localpart,
e2785e04f92e VMM/…: re-indented long queries and error messages.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 254
diff changeset
   100
                    'i_chars': i_chars}, LOCALPART_INVALID)
253
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
   101
    return localpart
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
   102
58d1b6f41664 VMM: moved check_localpart() to the EmailAddress module.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 218
diff changeset
   103
194
6c06edb5b2d2 VMM/EmailAddress: reworked once more.
Pascal Volk <neverseen@users.sourceforge.net>
parents: 193
diff changeset
   104
del _