diff -ur tmda.orig/CRYPTO tmda/CRYPTO
--- tmda.orig/CRYPTO	Thu Aug 21 16:52:14 2003
+++ tmda/CRYPTO	Thu Aug 21 21:01:25 2003
@@ -48,6 +48,26 @@
     1.  SENDERMAC is verified by matching it with a new HMAC generated
         against the sender's e-mail address.
 
+Domain Addresses:
+-----------------
+
+The format for a 'domain' address is:
+    
+    USERNAME-domain-DOMAINMAC@FOO.DOMAIN.DOM
+
+    (For example, jason-domain-8c54ac@mastaler.com)
+
+    DOMAINMAC is an HMAC of the domain's e-mail address.
+
+Incoming 'domain' messages are accepted if:
+
+    1.  DOMAINMAC is verified by matching it with a new HMAC generated
+        against the full domain of the sender's e-mail address.
+    2.  If the new HMAC does not match, one level of qualification is
+	stripped (eg, 'FOO.DOMAIN.DOM' -> 'DOMAIN.DOM') and a new HMAC
+	is generated and compared.  The process repeats until a match
+	is found or no more domain parts remain.
+
 Keyword Addresses:
 ------------------
 
diff -ur tmda.orig/TMDA/Address.py tmda/TMDA/Address.py
--- tmda.orig/TMDA/Address.py	Thu Aug 21 16:52:14 2003
+++ tmda/TMDA/Address.py	Thu Aug 21 21:51:44 2003
@@ -210,6 +210,40 @@
     def hmac(self):
         return self.local_parts[-1]
 
+class DomainAddress(TaggedAddress):
+    def __init__(self, address=''):
+	TaggedAddress.__init__(self, address)
+
+    def create(self, base, sender):
+	if not base:
+	    base = self.base()
+	(dummy, local, domain) = _split(str(base))
+	sender = str(sender).split('@')[-1]	# just domain
+	cookie = Cookie.make_sender_cookie(sender)
+	self.local_parts = [ local, Defaults.TAGS_DOMAIN[0].lower(), cookie ]
+	tagged_local = Defaults.RECIPIENT_DELIMITER.join(self.local_parts)
+	self.address = tagged_local + '@' + domain
+	return self
+
+    # attempt to verify the domain starting with the most qualified name
+    # (eg, 'machine.dept.example.com'), stripping qualifications (eg,
+    # 'dept.example.com') until there's a match or we run out of parts
+    #
+    def verify(self, sender):
+	hmac = self.local_parts[-1]
+	domain = sender.split('@')[-1]
+	dot = '.'
+	domain_parts = domain.lower().split(dot)
+	try_hmac = None	
+
+	while try_hmac != hmac and domain_parts:
+	  try_hmac = Cookie.make_sender_cookie(dot.join(domain_parts))
+	  del domain_parts[0]
+	if try_hmac != hmac:
+	  raise BadCryptoError, "Invalid cryptographic tag."
+
+    def hmac(self):
+	return self.local_parts[-1]
 
 
 def Factory(address = None, tag = None):
@@ -233,6 +267,9 @@
                 ['sender'] + map(lambda s: s.lower(), Defaults.TAGS_SENDER):
             addr_obj = SenderAddress(address)
         elif cookie_type in \
+                ['sender'] + map(lambda s: s.lower(), Defaults.TAGS_DOMAIN):
+            addr_obj = DomainAddress(address)
+        elif cookie_type in \
                 ['keyword'] + map(lambda s: s.lower(), Defaults.TAGS_KEYWORD):
             addr_obj = KeywordAddress(address)
         else:
diff -ur tmda.orig/TMDA/Defaults.py tmda/TMDA/Defaults.py
--- tmda.orig/TMDA/Defaults.py	Thu Aug 21 16:52:14 2003
+++ tmda/TMDA/Defaults.py	Thu Aug 21 20:38:48 2003
@@ -1425,6 +1425,19 @@
 if not vars().has_key('TAGS_SENDER'):
     TAGS_SENDER = ['sender']
 
+# TAGS_DOMAIN
+# A list of one or more strings to identify a domain address.  The
+# first element in the list will be used by `tmda-address' when
+# generating a new domain address.
+#
+# Example:
+#
+# TAGS_DOMAIN = ['domain', 'dom', 'D']
+#
+# Default is 'domain'
+if not vars().has_key('TAGS_DOMAIN'):
+    TAGS_DOMAIN = ['domain']
+
 # TERSE_SUMMARY_HEADERS
 # A list containing one or more message headers that should be
 # displayed by tmda-pending's `--terse option'.  Listed headers are
diff -ur tmda.orig/bin/tmda-address tmda/bin/tmda-address
--- tmda.orig/bin/tmda-address	Thu Aug 21 16:52:14 2003
+++ tmda/bin/tmda-address	Thu Aug 21 20:39:03 2003
@@ -87,11 +87,12 @@
     opts = None
     try:
 	opts, args = getopt.getopt(args,
-                                   'c:a:dk:s:hVn', ['config-file=',
+                                   'c:a:dk:s:D:hVn', ['config-file=',
                                                     'address=',
                                                     'dated',
                                                     'keyword=',
                                                     'sender=',
+                                                    'domain=',
                                                     'help',
                                                     'version',
                                                     'no-newline'])
@@ -143,6 +144,9 @@
 	elif opt in ('-s', '--sender'):
 	    tag = Defaults.TAGS_SENDER[0].lower()
 	    option = arg
+	elif opt in ('-D', '--domain'):
+	    tag = Defaults.TAGS_DOMAIN[0].lower()
+	    option = arg
 	elif opt in ('-n', '--no-newline'):
 	    print_newline = 0
 	opts.remove((opt, arg))
diff -ur tmda.orig/bin/tmda-check-address tmda/bin/tmda-check-address
--- tmda.orig/bin/tmda-check-address	Thu Aug 21 16:52:14 2003
+++ tmda/bin/tmda-check-address	Thu Aug 21 20:52:12 2003
@@ -42,7 +42,7 @@
 
     address is the address you want to check.
     
-    senderaddr is the sender address to verify if checking a sender style address.
+    senderaddr is the sender address to verify if checking a sender or domain style address.
 """
 
 import getopt
diff -ur tmda.orig/htdocs/config-client.ht tmda/htdocs/config-client.ht
--- tmda.orig/htdocs/config-client.ht	Thu Aug 21 16:52:14 2003
+++ tmda/htdocs/config-client.ht	Thu Aug 21 21:41:12 2003
@@ -55,6 +55,36 @@
 <em>python-list-admin@python.org</em>).
 </ul>
 
+<u>Domain Addresses</u>
+<ul>
+If you don't know precisely who the sender will be, or want to allow multiple
+senders in the same domain to send mail to one address, TMDA can tag your
+messages with a domain address.  Domain addresses can be used by any sender
+in the domain.
+
+Here is an example domain address:
+
+<blockquote><pre>
+jason-domain-2187d5@mastaler.com
+</pre></blockquote>
+
+This particular domain address will only accept messages from
+anyone <em>@whitehouse.gov</em>.  Other messages must go through
+the confirmation process.<br>
+Unlike sender addresses, domain addresses don't have to match exactly.
+A domain address for whitehouse.gov would also accept mail from the
+domain ovaloffice.whitehouse.gov, but not from senate.gov
+<br><br>
+
+Sender addresses are often used to subscribe to mailing lists.  This
+way, you don't have to worry that the subscription list might get
+harvested by spammers since only the mailing list software will be
+able to send messages there.  The address to use can be found in the
+<b>Return-Path</b> header of a mailing list message (e.g, subscribe to
+the Python list with a sender address based upon
+<em>python-list-admin@python.org</em>).
+</ul>
+
 <u>Keyword Addresses</u>
 <ul>
 TMDA can also tag your messages with a keyword address which will work
