Example #1
0
def sendmail_send(recipient, message, config=None, section='DEFAULT'):
    if config is None:
        config = _config.CONFIG
    message_bytes = _flatten(message)
    sendmail = [config.get(section, 'sendmail')]
    sendmail_config = config.get(section, 'sendmail_config')
    if sendmail_config:
        sendmail.extend(['-C', sendmail_config])
    sender_name, sender_addr = _parseaddr(config.get(section, 'from'))
    _LOG.debug('sending message to {} via {}'.format(recipient, sendmail))
    try:
        p = _subprocess.Popen(
            sendmail + ['-F', sender_name, '-f', sender_addr, recipient],
            stdin=_subprocess.PIPE,
            stdout=_subprocess.PIPE,
            stderr=_subprocess.STDOUT)
        stdout, _ = p.communicate(message_bytes)
        status = p.wait()
        _LOG.debug(stdout.decode())
        if status:
            if _LOG.level > logging.DEBUG:
                _LOG.error(stdout.decode())
            raise _error.SendmailError(status=status)
    except Exception as e:
        raise _error.SendmailError() from e
Example #2
0
def validate_email_address(email_id: str) -> str:
    if not email_id:
        raise AppException("Invalid email")
    email_id = email_id.lower()
    if "@" in _parseaddr(email_id)[1]:
        return email_id
    raise AppException("Invalid Email", HTTPStatus.BAD_REQUEST)
Example #3
0
def get_message(sender, recipient, subject, body, content_type="plain",
                extra_headers=None):
    """Generate a `Message` instance.

    All arguments should be Unicode strings (plain ASCII works as well).

    Only the real name part of sender and recipient addresses may
    contain non-ASCII characters.

    The email will be properly MIME encoded.

    The charset of the email will be the first one out of the list
    that can represent all the characters occurring in the email.
    """

    # Split real name (which is optional) and email address parts
    sender_name, sender_addr = _parseaddr(sender)
    recipient_name, recipient_addr = _parseaddr(recipient)

    sender_encoding = guess_encoding(sender_name)
    recipient_encoding = guess_encoding(recipient_name)
    subject_encoding = guess_encoding(subject)
    body_encoding = guess_encoding(body)

    # We must always pass Unicode strings to Header, otherwise it will
    # use RFC 2047 encoding even on plain ASCII strings.
    sender_name = str(_Header(sender_name, sender_encoding).encode())
    recipient_name = str(_Header(recipient_name, recipient_encoding).encode())

    # Make sure email addresses do not contain non-ASCII characters
    sender_addr.encode('ascii')
    recipient_addr.encode('ascii')

    # Create the message ('plain' stands for Content-Type: text/plain)
    message = _MIMEText(body, content_type, body_encoding)
    message['From'] = _formataddr((sender_name, sender_addr))
    message['To'] = _formataddr((recipient_name, recipient_addr))
    message['Subject'] = _Header(subject, subject_encoding)

    if extra_headers:
        for key, value in extra_headers.items():
            encoding = guess_encoding(value)
            message[key] = _Header(value, encoding)
    return message
Example #4
0
 def _new_digest(self):
     digest = _MIMEMultipart('digest')
     digest['To'] = _formataddr(_parseaddr(self.to))  # Encodes with utf-8 as necessary
     digest['Subject'] = 'digest for {}'.format(self.name)
     digest['Message-ID'] = '<{0}@{1}>'.format(_uuid.uuid4(), platform.node())
     digest['User-Agent'] = self.user_agent
     digest['List-ID'] = '<{}.localhost>'.format(self.name)
     digest['List-Post'] = 'NO (posting not allowed on this list)'
     digest['X-RSS-Feed'] = self.url
     return digest
Example #5
0
def sendmail_send(sender, recipient, message, config=None, section='DEFAULT'):
    if config is None:
        config = _config.CONFIG
    message_bytes = _flatten(message)
    sendmail = config.get(section, 'sendmail')
    sender_name,sender_addr = _parseaddr(sender)
    _LOG.debug(
        'sending message to {} via {}'.format(recipient, sendmail))
    try:
        p = _subprocess.Popen(
            [sendmail, '-F', sender_name, '-f', sender_addr, recipient],
            stdin=_subprocess.PIPE, stdout=_subprocess.PIPE,
            stderr=_subprocess.PIPE)
        stdout,stderr = p.communicate(message_bytes)
        status = p.wait()
        if status:
            raise _error.SendmailError(
                status=status, stdout=stdout, stderr=stderr)
    except Exception as e:
        raise _error.SendmailError() from e
Example #6
0
def sendmail_send(sender, recipient, message, config=None, section='DEFAULT'):
    if config is None:
        config = _config.CONFIG
    message_bytes = _flatten(message)
    sendmail = config.get(section, 'sendmail')
    sender_name,sender_addr = _parseaddr(sender)
    _LOG.debug(
        'sending message to {} via {}'.format(recipient, sendmail))
    try:
        p = _subprocess.Popen(
            [sendmail, '-F', sender_name, '-f', sender_addr, recipient],
            stdin=_subprocess.PIPE, stdout=_subprocess.PIPE,
            stderr=_subprocess.PIPE)
        stdout,stderr = p.communicate(message_bytes)
        status = p.wait()
        if status:
            raise _error.SendmailError(
                status=status, stdout=stdout, stderr=stderr)
    except Exception as e:
        raise _error.SendmailError() from e
Example #7
0
"Catalyst is the release building tool used by Gentoo Linux"

import codecs as _codecs
from distutils.core import setup as _setup
from email.utils import parseaddr as _parseaddr
import itertools as _itertools
import os as _os

from catalyst import __version__, __maintainer__


_this_dir = _os.path.dirname(__file__)
_package_name = 'catalyst'
_maintainer_name, _maintainer_email = _parseaddr(__maintainer__)


def _posix_path(path):
	"""Convert a native path to a POSIX path

	Distutils wants all paths to be written in the Unix convention
	(i.e. slash-separated) [1], so that's what we'll do here.

	[1]: http://docs.python.org/2/distutils/setupscript.html#writing-the-setup-script
	"""
	if _os.path.sep != '/':
		return path.replace(_os.path.sep, '/')
	return path


def _files(prefix, root):
	"""Iterate through all the file paths under `root`
Example #8
0
def get_message(sender, recipient, subject, body, content_type,
                extra_headers=None, config=None, section='DEFAULT'):
    """Generate a `Message` instance.

    All arguments should be Unicode strings (plain ASCII works as well).

    Only the real name part of sender and recipient addresses may contain
    non-ASCII characters.

    The email will be properly MIME encoded.

    The charset of the email will be the first one out of the list
    that can represent all the characters occurring in the email.

    >>> message = get_message(
    ...     sender='John <*****@*****.**>', recipient='Ζεύς <*****@*****.**>',
    ...     subject='Testing',
    ...     body='Hello, world!\\n',
    ...     content_type='plain',
    ...     extra_headers={'Approved': '*****@*****.**'})
    >>> print(message.as_string())  # doctest: +REPORT_UDIFF
    MIME-Version: 1.0
    Content-Type: text/plain; charset="us-ascii"
    Content-Transfer-Encoding: 7bit
    From: John <*****@*****.**>
    To: =?utf-8?b?zpbOtc+Nz4I=?= <*****@*****.**>
    Subject: Testing
    Approved: [email protected]
    <BLANKLINE>
    Hello, world!
    <BLANKLINE>
    """
    if config is None:
        config = _config.CONFIG
    if section not in config.sections():
        section = 'DEFAULT'
    encodings = [
        x.strip() for x in config.get(section, 'encodings').split(',')]

    # Split real name (which is optional) and email address parts
    sender_name,sender_addr = _parseaddr(sender)
    recipient_name,recipient_addr = _parseaddr(recipient)

    sender_encoding = guess_encoding(sender_name, encodings)
    recipient_encoding = guess_encoding(recipient_name, encodings)
    subject_encoding = guess_encoding(subject, encodings)
    body_encoding = guess_encoding(body, encodings)

    # We must always pass Unicode strings to Header, otherwise it will
    # use RFC 2047 encoding even on plain ASCII strings.
    sender_name = str(_Header(sender_name, sender_encoding).encode())
    recipient_name = str(_Header(recipient_name, recipient_encoding).encode())

    # Make sure email addresses do not contain non-ASCII characters
    sender_addr.encode('ascii')
    recipient_addr.encode('ascii')

    # Create the message ('plain' stands for Content-Type: text/plain)
    message = _MIMEText(body, content_type, body_encoding)
    message['From'] = _formataddr((sender_name, sender_addr))
    message['To'] = _formataddr((recipient_name, recipient_addr))
    message['Subject'] = _Header(subject, subject_encoding)
    if config.getboolean(section, 'use-8bit'):
        del message['Content-Transfer-Encoding']
        charset = _Charset(body_encoding)
        charset.body_encoding = _email_encoders.encode_7or8bit
        message.set_payload(body, charset=charset)
    if extra_headers:
        for key,value in extra_headers.items():
            encoding = guess_encoding(value, encodings)
            message[key] = _Header(value, encoding)
    return message
Example #9
0
def get_message(sender,
                recipient,
                subject,
                body,
                content_type,
                extra_headers=None,
                config=None,
                section='DEFAULT'):
    """Generate a `Message` instance.

    All arguments should be Unicode strings (plain ASCII works as well).

    Only the real name part of sender and recipient addresses may contain
    non-ASCII characters.

    The email will be properly MIME encoded.

    The charset of the email will be the first one out of the list
    that can represent all the characters occurring in the email.

    >>> message = get_message(
    ...     sender='John <*****@*****.**>', recipient='Ζεύς <*****@*****.**>',
    ...     subject='Testing',
    ...     body='Hello, world!\\n',
    ...     content_type='plain',
    ...     extra_headers={'Approved': '*****@*****.**'})
    >>> print(message.as_string())  # doctest: +REPORT_UDIFF
    MIME-Version: 1.0
    Content-Type: text/plain; charset="us-ascii"
    Content-Transfer-Encoding: 7bit
    From: John <*****@*****.**>
    To: =?utf-8?b?zpbOtc+Nz4I=?= <*****@*****.**>
    Subject: Testing
    Approved: [email protected]
    <BLANKLINE>
    Hello, world!
    <BLANKLINE>
    """
    if config is None:
        config = _config.CONFIG
    if section not in config.sections():
        section = 'DEFAULT'
    encodings = [
        x.strip() for x in config.get(section, 'encodings').split(',')
    ]

    # Split real name (which is optional) and email address parts
    sender_name, sender_addr = _parseaddr(sender)
    recipient_list = []
    for recipient_name, recipient_addr in _getaddresses([recipient]):
        recipient_encoding = guess_encoding(recipient_name, encodings)
        recipient_name = str(
            _Header(recipient_name, recipient_encoding).encode())
        recipient_addr.encode('ascii')
        recipient_list.append(_formataddr((recipient_name, recipient_addr)))

    sender_encoding = guess_encoding(sender_name, encodings)
    recipient_encoding = guess_encoding(recipient_name, encodings)
    subject_encoding = guess_encoding(subject, encodings)
    body_encoding = guess_encoding(body, encodings)

    # We must always pass Unicode strings to Header, otherwise it will
    # use RFC 2047 encoding even on plain ASCII strings.
    sender_name = str(_Header(sender_name, sender_encoding).encode())

    # Make sure email addresses do not contain non-ASCII characters
    sender_addr.encode('ascii')

    # Create the message ('plain' stands for Content-Type: text/plain)
    message = _MIMEText(body, content_type, body_encoding)
    message['From'] = _formataddr((sender_name, sender_addr))
    message['To'] = ', '.join(recipient_list)
    message['Subject'] = _Header(subject, subject_encoding)
    if config.getboolean(section, 'use-8bit'):
        del message['Content-Transfer-Encoding']
        charset = _Charset(body_encoding)
        charset.body_encoding = _email_encoders.encode_7or8bit
        message.set_payload(body, charset=charset)
    if extra_headers:
        for key, value in extra_headers.items():
            encoding = guess_encoding(value, encodings)
            message[key] = _Header(value, encoding)
    return message
Example #10
0
def _get_message_person(course, message, trust_admin_from=True):
    """Get the `Person` that sent the message.

    We use 'Return-Path' (envelope from) instead of the message's From
    header, because it's more consistent and harder to fake.  However,
    there may be times when you *want* to send a message in somebody
    elses name.

    For example, if a student submitted an assignment from an
    unexpected address, you might add that address to their entry in
    your course config, and then bounce the message back into
    pygrader.  In this case, the From header will still be the
    student, but the 'Return-Path' will be you.  With
    `trust_admin_from` (on by default), messages who's 'Return-Path'
    matches a professor or TA will have their 'From' line used to find
    the final person responsible for the message.

    >>> from pygrader.model.course import Course
    >>> from pygrader.model.person import Person
    >>> from pgp_mime import encodedMIMEText

    >>> course = Course(people=[
    ...     Person(
    ...         name='Gandalf', emails=['*****@*****.**'], groups=['professors']),
    ...     Person(name='Bilbo', emails=['*****@*****.**']),
    ...     ])
    >>> message = encodedMIMEText('testing')
    >>> message['Return-Path'] = '<*****@*****.**>'
    >>> message['From'] = 'Bill <*****@*****.**>'
    >>> message['Message-ID'] = '<*****@*****.**>'

    >>> person = _get_message_person(course=course, message=message)
    >>> print(person)
    <Person Bilbo>

    >>> person = _get_message_person(
    ...     course=course, message=message, trust_admin_from=False)
    >>> print(person)
    <Person Gandalf>
    """
    sender = message['return-path']  # RFC 822
    if sender is None:
        raise NoReturnPath(message)
    sender = sender[1:-1]  # strip wrapping '<' and '>'
    people = list(course.find_people(email=sender))
    if len(people) == 0:
        raise UnregisteredAddress(message=message, address=sender)
    if len(people) > 1:
        raise AmbiguousAddress(message=message, address=sender, people=people)
    person = people[0]
    if trust_admin_from and person.is_admin():
        mid = message['message-id']
        from_headers = message.get_all('from')
        if len(from_headers) == 0:
            _LOG.debug("no 'From' headers in {}".format(mid))
        elif len(from_headers) > 1:
            _LOG.debug("multiple 'From' headers in {}".format(mid))
        else:
            name,address = _parseaddr(from_headers[0])
            people = list(course.find_people(email=address))
            if len(people) == 0:
                _LOG.debug("'From' address {} is unregistered".format(address))
            if len(people) > 1:
                _LOG.debug("'From' address {} is ambiguous".format(address))
            _LOG.debug('message from {} treated as being from {}'.format(
                    person, people[0]))
            person = people[0]
    _LOG.debug('message from {}'.format(person))
    return person
Example #11
0
"""Catalyst is a release building tool used by Gentoo Linux"""

from __future__ import print_function

import codecs as _codecs
from distutils.core import setup as _setup, Command as _Command
from email.utils import parseaddr as _parseaddr
import os as _os

from catalyst import __version__, __maintainer__
from catalyst.version import set_release_version as _set_release_version
from catalyst.version import get_version as _get_version

_this_dir = _os.path.dirname(__file__)
_package_name = 'catalyst'
_maintainer_name, _maintainer_email = _parseaddr(__maintainer__)


def _posix_path(path):
    """Convert a native path to a POSIX path

	Distutils wants all paths to be written in the Unix convention
	(i.e. slash-separated) [1], so that's what we'll do here.

	[1]: https://docs.python.org/2/distutils/setupscript.html
	"""
    if _os.path.sep != '/':
        return path.replace(_os.path.sep, '/')
    return path

Example #12
0
def _get_message_person(course, message, trust_admin_from=True):
    """Get the `Person` that sent the message.

    We use 'Return-Path' (envelope from) instead of the message's From
    header, because it's more consistent and harder to fake.  However,
    there may be times when you *want* to send a message in somebody
    elses name.

    For example, if a student submitted an assignment from an
    unexpected address, you might add that address to their entry in
    your course config, and then bounce the message back into
    pygrader.  In this case, the From header will still be the
    student, but the 'Return-Path' will be you.  With
    `trust_admin_from` (on by default), messages who's 'Return-Path'
    matches a professor or TA will have their 'From' line used to find
    the final person responsible for the message.

    >>> from pygrader.model.course import Course
    >>> from pygrader.model.person import Person
    >>> from pgp_mime import encodedMIMEText

    >>> course = Course(people=[
    ...     Person(
    ...         name='Gandalf', emails=['*****@*****.**'], groups=['professors']),
    ...     Person(name='Bilbo', emails=['*****@*****.**']),
    ...     ])
    >>> message = encodedMIMEText('testing')
    >>> message['Return-Path'] = '<*****@*****.**>'
    >>> message['From'] = 'Bill <*****@*****.**>'
    >>> message['Message-ID'] = '<*****@*****.**>'

    >>> person = _get_message_person(course=course, message=message)
    >>> print(person)
    <Person Bilbo>

    >>> person = _get_message_person(
    ...     course=course, message=message, trust_admin_from=False)
    >>> print(person)
    <Person Gandalf>
    """
    sender = message['return-path']  # RFC 822
    if sender is None:
        raise NoReturnPath(message)
    sender = sender[1:-1]  # strip wrapping '<' and '>'
    people = list(course.find_people(email=sender))
    if len(people) == 0:
        raise UnregisteredAddress(message=message, address=sender)
    if len(people) > 1:
        raise AmbiguousAddress(message=message, address=sender, people=people)
    person = people[0]
    if trust_admin_from and person.is_admin():
        mid = message['message-id']
        from_headers = message.get_all('from')
        if len(from_headers) == 0:
            _LOG.debug("no 'From' headers in {}".format(mid))
        elif len(from_headers) > 1:
            _LOG.debug("multiple 'From' headers in {}".format(mid))
        else:
            name, address = _parseaddr(from_headers[0])
            people = list(course.find_people(email=address))
            if len(people) == 0:
                _LOG.debug("'From' address {} is unregistered".format(address))
            if len(people) > 1:
                _LOG.debug("'From' address {} is ambiguous".format(address))
            _LOG.debug('message from {} treated as being from {}'.format(
                person, people[0]))
            person = people[0]
    _LOG.debug('message from {}'.format(person))
    return person
Example #13
0
def validate_email_address(email_id: str) -> str:
    if "@" in _parseaddr(email_id)[1]:
        return email_id
    raise AppException("Invalid Email")