Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bounce.py 3.1KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # -*- test-case-name: twisted.mail.test.test_bounce -*-
  2. #
  3. # Copyright (c) Twisted Matrix Laboratories.
  4. # See LICENSE for details.
  5. """
  6. Support for bounce message generation.
  7. """
  8. import email.utils
  9. import os
  10. import time
  11. from io import SEEK_END, SEEK_SET, StringIO
  12. from twisted.mail import smtp
  13. BOUNCE_FORMAT = """\
  14. From: postmaster@{failedDomain}
  15. To: {failedFrom}
  16. Subject: Returned Mail: see transcript for details
  17. Message-ID: {messageID}
  18. Content-Type: multipart/report; report-type=delivery-status;
  19. boundary="{boundary}"
  20. --{boundary}
  21. {transcript}
  22. --{boundary}
  23. Content-Type: message/delivery-status
  24. Arrival-Date: {ctime}
  25. Final-Recipient: RFC822; {failedTo}
  26. """
  27. def generateBounce(message, failedFrom, failedTo, transcript="", encoding="utf-8"):
  28. """
  29. Generate a bounce message for an undeliverable email message.
  30. @type message: a file-like object
  31. @param message: The undeliverable message.
  32. @type failedFrom: L{bytes} or L{unicode}
  33. @param failedFrom: The originator of the undeliverable message.
  34. @type failedTo: L{bytes} or L{unicode}
  35. @param failedTo: The destination of the undeliverable message.
  36. @type transcript: L{bytes} or L{unicode}
  37. @param transcript: An error message to include in the bounce message.
  38. @type encoding: L{str} or L{unicode}
  39. @param encoding: Encoding to use, default: utf-8
  40. @rtype: 3-L{tuple} of (E{1}) L{bytes}, (E{2}) L{bytes}, (E{3}) L{bytes}
  41. @return: The originator, the destination and the contents of the bounce
  42. message. The destination of the bounce message is the originator of
  43. the undeliverable message.
  44. """
  45. if isinstance(failedFrom, bytes):
  46. failedFrom = failedFrom.decode(encoding)
  47. if isinstance(failedTo, bytes):
  48. failedTo = failedTo.decode(encoding)
  49. if not transcript:
  50. transcript = """\
  51. I'm sorry, the following address has permanent errors: {failedTo}.
  52. I've given up, and I will not retry the message again.
  53. """.format(
  54. failedTo=failedTo
  55. )
  56. failedAddress = email.utils.parseaddr(failedTo)[1]
  57. data = {
  58. "boundary": "{}_{}_{}".format(time.time(), os.getpid(), "XXXXX"),
  59. "ctime": time.ctime(time.time()),
  60. "failedAddress": failedAddress,
  61. "failedDomain": failedAddress.split("@", 1)[1],
  62. "failedFrom": failedFrom,
  63. "failedTo": failedTo,
  64. "messageID": smtp.messageid(uniq="bounce"),
  65. "message": message,
  66. "transcript": transcript,
  67. }
  68. fp = StringIO()
  69. fp.write(BOUNCE_FORMAT.format(**data))
  70. orig = message.tell()
  71. message.seek(0, SEEK_END)
  72. sz = message.tell()
  73. message.seek(orig, SEEK_SET)
  74. if sz > 10000:
  75. while 1:
  76. line = message.readline()
  77. if isinstance(line, bytes):
  78. line = line.decode(encoding)
  79. if len(line) <= 0:
  80. break
  81. fp.write(line)
  82. else:
  83. messageContent = message.read()
  84. if isinstance(messageContent, bytes):
  85. messageContent = messageContent.decode(encoding)
  86. fp.write(messageContent)
  87. return b"", failedFrom.encode(encoding), fp.getvalue().encode(encoding)