Index: Lib/email/utils.py =================================================================== --- Lib/email/utils.py (revision 76258) +++ Lib/email/utils.py (working copy) @@ -172,10 +172,22 @@ +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock +_seq_lock = Lock() + +def _gen_seq(): + while True: + for number in xrange(100000): + yield number +_seq = _gen_seq() + def make_msgid(idstring=None): """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: - <20020201195627.33539.96671@nightshade.la.mastaler.com> + <20020201195627.137.33539.96671@nightshade.la.mastaler.com> Optional idstring if given is a string used to strengthen the uniqueness of the message id. @@ -184,12 +196,14 @@ utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval)) pid = os.getpid() randint = random.randrange(100000) + with _seq_lock: + seqint = next(_seq) if idstring is None: idstring = '' else: idstring = '.' + idstring idhost = socket.getfqdn() - msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, idhost) + msgid = '<%s.%s.%s.%s%s@%s>' % (utcdate, pid, randint, seqint, idstring, idhost) return msgid Index: Lib/email/test/test_email.py =================================================================== --- Lib/email/test/test_email.py (revision 76291) +++ Lib/email/test/test_email.py (working copy) @@ -10,6 +10,8 @@ import unittest import warnings from cStringIO import StringIO +try: from threading import Thread +except ImportError: from dummy_threading import Thread import email @@ -2270,6 +2272,30 @@ addrs = Utils.getaddresses(['User ((nested comment)) ']) eq(addrs[0][1], 'foo@bar.com') + def test_utils_make_msgid(self): + # Test make_msgid uniqueness, even with multiple threads + + class MsgidsThread(Thread): + def run(self): + # generate msgids for 3 seconds + self.msgids = [] + append = self.msgids.append + make_msgid = Utils.make_msgid + clock = time.clock + + tfin = clock() + 3.0 + while clock() < tfin: + append(make_msgid()) + + eq = self.assertEqual + threads = [MsgidsThread() for i in range(5)] + for t in threads: + t.start() + for t in threads: + t.join() + all_ids = sum([t.msgids for t in threads], []) + eq(len(set(all_ids)), len(all_ids)) + def test_utils_quote_unquote(self): eq = self.assertEqual msg = Message()