コード例 #1
0
ファイル: verp.py プロジェクト: P-EB/mailman3-core
    def _get_sender(self, mlist, msg, msgdata):
        """Return the recipient's address VERP encoded in the sender.

        :param mlist: The mailing list being delivered to.
        :type mlist: `IMailingList`
        :param msg: The original message being delivered.
        :type msg: `Message`
        :param msgdata: Additional message metadata for this delivery.
        :type msgdata: dictionary
        """
        sender = super(VERPMixin, self)._get_sender(mlist, msg, msgdata)
        if msgdata.get("verp", False):
            log.debug("VERPing %s", msg.get("message-id"))
            recipient = msgdata["recipient"]
            sender_mailbox, sender_domain = split_email(sender)
            # Encode the recipient's address for VERP.
            recipient_mailbox, recipient_domain = split_email(recipient)
            if recipient_domain is None:
                # The recipient address is not fully-qualified.  We can't
                # deliver it to this person, nor can we craft a valid verp
                # header.  I don't think there's much we can do except ignore
                # this recipient.
                log.info("Skipping VERP delivery to unqual recip: %s", recipient)
                return sender
            return "{0}@{1}".format(
                expand(
                    config.mta.verp_format,
                    dict(bounces=sender_mailbox, local=recipient_mailbox, domain=DOT.join(recipient_domain)),
                ),
                DOT.join(sender_domain),
            )
        else:
            return sender
コード例 #2
0
ファイル: verp.py プロジェクト: omunroe-com/mlman
    def _get_sender(self, mlist, msg, msgdata):
        """Return the recipient's address VERP encoded in the sender.

        :param mlist: The mailing list being delivered to.
        :type mlist: `IMailingList`
        :param msg: The original message being delivered.
        :type msg: `Message`
        :param msgdata: Additional message metadata for this delivery.
        :type msgdata: dictionary
        """
        sender = super()._get_sender(mlist, msg, msgdata)
        if msgdata.get('verp', False):
            log.debug('VERPing %s', msg.get('message-id'))
            recipient = msgdata['recipient']
            sender_mailbox, sender_domain = split_email(sender)
            # Encode the recipient's address for VERP.
            recipient_mailbox, recipient_domain = split_email(recipient)
            if recipient_domain is None:
                # The recipient address is not fully-qualified.  We can't
                # deliver it to this person, nor can we craft a valid verp
                # header.  I don't think there's much we can do except ignore
                # this recipient.
                log.info('Skipping VERP delivery to unqual recip: %s',
                         recipient)
                return sender
            return '{0}@{1}'.format(
                expand(
                    config.mta.verp_format, mlist,
                    dict(bounces=sender_mailbox,
                         local=recipient_mailbox,
                         domain=DOT.join(recipient_domain))),
                DOT.join(sender_domain))
        else:
            return sender
コード例 #3
0
def send_probe(member, msg):
    """Send a VERP probe to the member.

    :param member: The member to send the probe to.  From this object, both
        the user and the mailing list can be determined.
    :type member: IMember
    :param msg: The bouncing message that caused the probe to be sent.
    :type msg:
    :return: The token representing this probe in the pendings database.
    :rtype: string
    """
    mlist = getUtility(IListManager).get_by_list_id(
        member.mailing_list.list_id)
    text = make(
        'probe.txt',
        mlist,
        member.preferred_language.code,
        listname=mlist.fqdn_listname,
        address=member.address.email,
        optionsurl=member.options_url,
        owneraddr=mlist.owner_address,
    )
    message_id = msg['message-id']
    if isinstance(message_id, bytes):
        message_id = message_id.decode('ascii')
    pendable = _ProbePendable(
        # We can only pend unicodes.
        member_id=member.member_id.hex,
        message_id=message_id,
    )
    token = getUtility(IPendings).add(pendable)
    mailbox, domain_parts = split_email(mlist.bounces_address)
    probe_sender = Template(config.mta.verp_probe_format).safe_substitute(
        bounces=mailbox,
        token=token,
        domain=DOT.join(domain_parts),
    )
    # Calculate the Subject header, in the member's preferred language.
    with _.using(member.preferred_language.code):
        subject = _('$mlist.display_name mailing list probe message')
    # Craft the probe message.  This will be a multipart where the first part
    # is the probe text and the second part is the message that caused this
    # probe to be sent.
    probe = UserNotification(member.address.email,
                             probe_sender,
                             subject,
                             lang=member.preferred_language)
    probe.set_type('multipart/mixed')
    notice = MIMEText(text, _charset=mlist.preferred_language.charset)
    probe.attach(notice)
    probe.attach(MIMEMessage(msg))
    # Probes should not have the Precedence: bulk header.
    probe.send(mlist,
               envsender=probe_sender,
               verp=False,
               probe_token=token,
               add_precedence=False)
    return token
コード例 #4
0
ファイル: validate.py プロジェクト: kaushikmit/mailman
 def is_valid(self, email):
     """See `IEmailValidator`."""
     if not email or " " in email:
         return False
     if _badchars.search(email) or email[0] == "-":
         return False
     user, domain_parts = split_email(email)
     # Local, unqualified addresses are not allowed.
     if not domain_parts:
         return False
     if len(domain_parts) < 2:
         return False
     return True
コード例 #5
0
ファイル: validate.py プロジェクト: TommyLike/mailman
 def is_valid(self, email):
     """See `IEmailValidator`."""
     if not email or ' ' in email:
         return False
     if _badchars.search(email) or email[0] == '-':
         return False
     user, domain_parts = split_email(email)
     # Local, unqualified addresses are not allowed.
     if not domain_parts:
         return False
     if len(domain_parts) < 2:
         return False
     return True
コード例 #6
0
ファイル: bounces.py プロジェクト: maxking/mailman
def send_probe(member, msg):
    """Send a VERP probe to the member.

    :param member: The member to send the probe to.  From this object, both
        the user and the mailing list can be determined.
    :type member: IMember
    :param msg: The bouncing message that caused the probe to be sent.
    :type msg:
    :return: The token representing this probe in the pendings database.
    :rtype: string
    """
    mlist = getUtility(IListManager).get_by_list_id(
        member.mailing_list.list_id)
    text = make('probe.txt', mlist, member.preferred_language.code,
                listname=mlist.fqdn_listname,
                address=member.address.email,
                optionsurl=member.options_url,
                owneraddr=mlist.owner_address,
                )
    message_id = msg['message-id']
    if isinstance(message_id, bytes):
        message_id = message_id.decode('ascii')
    pendable = _ProbePendable(
        # We can only pend unicodes.
        member_id=member.member_id.hex,
        message_id=message_id,
        )
    token = getUtility(IPendings).add(pendable)
    mailbox, domain_parts = split_email(mlist.bounces_address)
    probe_sender = Template(config.mta.verp_probe_format).safe_substitute(
        bounces=mailbox,
        token=token,
        domain=DOT.join(domain_parts),
        )
    # Calculate the Subject header, in the member's preferred language.
    with _.using(member.preferred_language.code):
        subject = _('$mlist.display_name mailing list probe message')
    # Craft the probe message.  This will be a multipart where the first part
    # is the probe text and the second part is the message that caused this
    # probe to be sent.
    probe = UserNotification(member.address.email, probe_sender,
                             subject, lang=member.preferred_language)
    probe.set_type('multipart/mixed')
    notice = MIMEText(text, _charset=mlist.preferred_language.charset)
    probe.attach(notice)
    probe.attach(MIMEMessage(msg))
    # Probes should not have the Precedence: bulk header.
    probe.send(mlist, envsender=probe_sender, verp=False, probe_token=token,
               add_precedence=False)
    return token
コード例 #7
0
 def is_valid(self, email):
     """See `IEmailValidator`."""
     if not email:
         return False
     user, domain_parts = split_email(email)
     if not user or len(_valid_local.sub('', user)) > 0:
         return False
     # Local, unqualified addresses are not allowed.
     if not domain_parts:
         return False
     if len(domain_parts) < 2:
         return False
     for p in domain_parts:
         if len(p) == 0 or p[0] == '-' or len(_valid_domain.sub('', p)) > 0:
             return False
     return True
コード例 #8
0
ファイル: bounces.py プロジェクト: Nakaner/mailman3-debian
    def get_verp(self, mlist, msg):
        """Extract a set of VERP bounce addresses.

        :param mlist: The mailing list being checked.
        :type mlist: `IMailingList`
        :param msg: The message being parsed.
        :type msg: `email.message.Message`
        :return: The set of addresses extracted from the VERP headers.
        :rtype: set of strings
        """
        blocal, bdomain = split_email(mlist.bounces_address)
        values = set()
        verp_matches = set()
        for header in ('to', 'delivered-to', 'envelope-to', 'apparently-to'):
            values.update(msg.get_all(header, []))
        for field in values:
            address = parseaddr(field)[1]
            if not address:
                # This header was empty.
                continue
            mo = self._cre.search(address)
            if not mo:
                # This did not match the VERP regexp.
                continue
            try:
                if blocal != mo.group('bounces'):
                    # This was not a bounce to our mailing list.
                    continue
                original_address = self._get_address(mo)
            except IndexError:
                elog.error('Bad VERP pattern: {0}'.format(self._pattern))
                return set()
            else:
                if original_address is not None:
                    verp_matches.add(original_address)
        return verp_matches
コード例 #9
0
ファイル: bounces.py プロジェクト: maxking/mailman
    def get_verp(self, mlist, msg):
        """Extract a set of VERP bounce addresses.

        :param mlist: The mailing list being checked.
        :type mlist: `IMailingList`
        :param msg: The message being parsed.
        :type msg: `email.message.Message`
        :return: The set of addresses extracted from the VERP headers.
        :rtype: set of strings
        """
        blocal, bdomain = split_email(mlist.bounces_address)
        values = set()
        verp_matches = set()
        for header in ('to', 'delivered-to', 'envelope-to', 'apparently-to'):
            values.update(msg.get_all(header, []))
        for field in values:
            address = parseaddr(field)[1]
            if not address:
                # This header was empty.
                continue
            mo = self._cre.search(address)
            if not mo:
                # This did not match the VERP regexp.
                continue
            try:
                if blocal != mo.group('bounces'):
                    # This was not a bounce to our mailing list.
                    continue
                original_address = self._get_address(mo)
            except IndexError:
                elog.error('Bad VERP pattern: {0}'.format(self._pattern))
                return set()
            else:
                if original_address is not None:
                    verp_matches.add(original_address)
        return verp_matches
コード例 #10
0
 def test_no_at_split(self):
     self.assertEqual(split_email('anne'), ('anne', None))
コード例 #11
0
 def test_normal_split(self):
     self.assertEqual(split_email('*****@*****.**'),
                      ('anne', ['example', 'com']))
     self.assertEqual(split_email('*****@*****.**'),
                      ('anne', ['foo', 'example', 'com']))
コード例 #12
0
def send_probe(member, msg=None, message_id=None):
    """Send a VERP probe to the member.

    :param member: The member to send the probe to.  From this object, both
        the user and the mailing list can be determined.
    :type member: IMember
    :param msg: The bouncing message that caused the probe to be sent.
    :type msg:
    :param message_id: MessageID of the bouncing message.
    :type message_id: str
    :return: The token representing this probe in the pendings database.
    :rtype: string
    """
    if (message_id or msg) is None:
        raise ValueError('Required at least one of "message_id" and "msg".')
    mlist = getUtility(IListManager).get_by_list_id(
        member.mailing_list.list_id)
    template = getUtility(ITemplateLoader).get(
        'list:user:notice:probe', mlist,
        language=member.preferred_language.code,
        # For backward compatibility.
        code=member.preferred_language.code,
        )
    text = wrap(expand(template, mlist, dict(
        sender_email=member.address.email,
        # For backward compatibility.
        address=member.address.email,
        email=member.address.email,
        owneraddr=mlist.owner_address,
        )))
    if message_id is None:
        message_id = msg['message-id']
    if isinstance(message_id, bytes):
        message_id = message_id.decode('ascii')
    pendable = _ProbePendable(
        # We can only pend unicodes.
        member_id=member.member_id.hex,
        message_id=message_id,
        )
    token = getUtility(IPendings).add(pendable)
    mailbox, domain_parts = split_email(mlist.bounces_address)
    probe_sender = Template(config.mta.verp_probe_format).safe_substitute(
        bounces=mailbox,
        token=token,
        domain=DOT.join(domain_parts),
        )
    # Calculate the Subject header, in the member's preferred language.
    with _.using(member.preferred_language.code):
        subject = _('$mlist.display_name mailing list probe message')
    # Craft the probe message.  This will be a multipart where the first part
    # is the probe text and the second part is the message that caused this
    # probe to be sent, if it provied.
    probe = UserNotification(member.address.email, probe_sender,
                             subject, lang=member.preferred_language)
    probe.set_type('multipart/mixed')
    notice = MIMEText(text, _charset=member.preferred_language.charset)
    probe.attach(notice)
    if msg is not None:
        probe.attach(MIMEMessage(msg))
    # Probes should not have the Precedence: bulk header.
    probe.send(mlist, sender=probe_sender, verp=False, probe_token=token,
               add_precedence=False)
    # When we send a probe, we reset the score.
    member.bounce_score = 0
    return token
コード例 #13
0
ファイル: test_email.py プロジェクト: aregee/Mailman
 def test_no_at_split(self):
     self.assertEqual(split_email('anne'), ('anne', None))
コード例 #14
0
ファイル: test_email.py プロジェクト: aregee/Mailman
 def test_normal_split(self):
     self.assertEqual(split_email('*****@*****.**'),
                      ('anne', ['example', 'com']))
     self.assertEqual(split_email('*****@*****.**'),
                      ('anne', ['foo', 'example', 'com']))
コード例 #15
0
 def test_no_at_split(self):
     self.assertEqual(split_email("anne"), ("anne", None))
コード例 #16
0
 def test_normal_split(self):
     self.assertEqual(split_email("*****@*****.**"), ("anne", ["example", "com"]))
     self.assertEqual(split_email("*****@*****.**"), ("anne", ["foo", "example", "com"]))