Beispiel #1
0
class TestDomains(unittest.TestCase):
    def setUp(self):
        self._client = Client('http://localhost:9001/3.0', 'restadmin',
                              'restpass')

    def test_no_domain(self):
        # Trying to get a non-existent domain returns a 404.
        #
        # We can't use `with self.assertRaises()` until we drop Python 2.6
        try:
            self._client.get_domain('example.org')
        except HTTPError as error:
            self.assertEqual(error.code, 404)
        else:
            raise AssertionError('Expected HTTPError 404')
Beispiel #2
0
class TestDomains(unittest.TestCase):
    def setUp(self):
        self._client = Client(
            'http://localhost:9001/3.0', 'restadmin', 'restpass')

    def test_no_domain(self):
        # Trying to get a non-existent domain returns a 404.
        #
        # We can't use `with self.assertRaises()` until we drop Python 2.6
        try:
            self._client.get_domain('example.org')
        except HTTPError as error:
            self.assertEqual(error.code, 404)
        else:
            raise AssertionError('Expected HTTPError 404')
Beispiel #3
0
else:    
    log.info('umbrella lists to process: ' + str(cp_lists.sections()))
# -----------------------------------------------------------

# connect to the mailman list server
client = Client(cp_config['mm_settings']['url'],
                cp_config['mm_settings']['user'],
                cp_config['mm_settings']['pass'])
        
try: 
    log.debug(client.system)    
except (MailmanConnectionError):    
    log.critical(MailmanConnectionError)
    raise SystemExit(0)
    
mm_domain = client.get_domain(cp_config['mm_settings']['domain'])
mm_lists = mm_domain.get_lists()
log.info('domain: ' + str(mm_domain))
log.debug('all lists in domain: ' + str(mm_lists))
log.debug('connected to : ' + str(client))


# -----------------------------------------------------------
# loop through the umbrella lists defined in the .ini file
# create the list if it does not exist
# update the lists with the information from the .ini file

for list in cp_lists.sections():    
    
    listname = helpers.cleanStr(cp_lists[list]['name'])
    
Beispiel #4
0
class MailMan(object):
    '''
  Use official mailman 3.0 api client
  '''
    client = None
    connected = False
    lists = []

    def __init__(self):

        # Create settings & check connection
        try:
            self.client = Client(settings.MAILMAN_URL, settings.MAILMAN_USER,
                                 settings.MAILMAN_PASS)
            logger.debug('Connected to mailman %(mailman_version)s' %
                         self.client.system)
        except:
            logger.error('Connection to mailman failed on %s' %
                         settings.MAILMAN_URL)
            return None

        self.connected = True

    def get_list(self, list_name):
        '''
    Retrieve a list using only its name
    '''
        if not self.connected:
            raise Exception('No mailman connection')

        list_name += '@%s' % settings.MAILMAN_DOMAIN
        ml = self.client.get_list(list_name)
        if not ml:
            raise Exception('Mailing list %s not found' % list_name)

        return ml

    def subscribe(self, list_name, email, full_name):
        '''
    Subscribe a member to a mailing list
    With full approval directly
    '''
        if not self.connected:
            raise Exception('No mailman connection')

        ml = self.get_list(list_name)
        return ml.subscribe(email,
                            full_name,
                            pre_verified=True,
                            pre_confirmed=True,
                            pre_approved=True)

    def unsubscribe(self, list_name, email):
        '''
    Unsubscribe a member from a mailing list
    '''
        if not self.connected:
            raise Exception('No mailman connection')

        ml = self.get_list(list_name)
        return ml.unsubscribe(email)

    def create_list(self, list_name, full_name, extra_settings=None):
        '''
    Create a new mailing list properly configured
    '''

        # Retrieve domain
        domain = self.client.get_domain(settings.MAILMAN_DOMAIN)
        if not domain:
            raise Exception('No mailman domain %s' % settings.MAILMAN_DOMAIN)

        # Get or create list on domain
        try:
            ml = domain.create_list(list_name)
        except:
            ml = self.get_list(list_name)

        # Configure mailing
        mls = ml.settings
        mls['default_member_action'] = 'accept'
        mls['default_nonmember_action'] = 'accept'
        mls['send_welcome_message'] = False
        mls['advertised'] = False
        mls['display_name'] = full_name
        mls['subject_prefix'] = '[%s] ' % full_name
        mls['reply_to_address'] = ml.fqdn_listname

        # Override
        if extra_settings:
            # No update on mls
            for k, v in extra_settings.items():
                mls[k] = v

        mls.save()

        return ml

    def delete_list(self, list_name):
        '''
    Delete a mailing list
    '''
        if not self.connected:
            raise Exception('No mailman connection')

        ml = self.get_list(list_name)
        return ml.delete()
def prepare_list():
    # pre-check before handling mailman core service
    if DEFAULT_DOMAIN_NAME == "":
        print("Must specify 'DEFAULT_DOMAIN_NAME' for mail list preparation.")
        exit(1)

    lists = str.split(str(DEFAULT_MAIL_LISTS).lower(), ",")
    if not os.path.exists(TEMPLATE_FOLDER_PATH):
        print("The template file folder 'TEMPLATE_FOLDER_PATH' must exits on"
              " local.")
        exit(1)

    if len(lists) == 0:
        # find out all of the lists from local folder.
        local_file = []
        for _, _, f in os.walk(os.path.join(os.getcwd(),
                                            TEMPLATE_FOLDER_PATH)):
            for file in f:
                if file.endswith(".txt") and not file.endswith("base.txt"):
                    local_file.append(os.path.splitext(file)[0])
        lists = list(set(local_file))

    client = Client(MAILMAN_CORE_ENDPOINT, MAILMAN_CORE_USER,
                    MAILMAN_CORE_PASSWORD)

    try:
        # Create default domain if not exists
        default_domain = client.get_domain(DEFAULT_DOMAIN_NAME)
    except HTTPError as err:
        if err.code == 404:
            default_domain = client.create_domain(DEFAULT_DOMAIN_NAME)
        else:
            print("unable to find domain {0}".format(err))
            exit(1)
    # Create default mail lists
    existing_lists = [el.list_name for el in client.lists]
    for l in lists:
        if l in existing_lists:
            print("skip creating list {0}, since it's already exist".format(l))
            continue
        else:
            print("starting to create mail list {0}".format(l))
            default_domain.create_list(l)

    # Patch template for lists
    for l in lists:
        # browse all of the dirs and find out the template files
        existing_folders = [
            f for f in os.listdir(
                os.path.join(os.getcwd(), TEMPLATE_FOLDER_PATH))
        ]
        for d in existing_folders:
            if not os.path.isdir(
                    os.path.join(os.getcwd(), TEMPLATE_FOLDER_PATH, d)):
                continue
            # check the list file exists
            local_file = get_template_file(d, l)
            if os.path.exists(local_file):
                patch_content = {
                    convert_name_to_substitution(d): get_templates_url(d, l)
                }
            elif os.path.exists(get_base_template_file(d)):
                patch_content = {
                    convert_name_to_substitution(d):
                    get_templates_url(d, "base")
                }
            else:
                continue
            patch_uri = "{0}/lists/{1}.{2}/uris".format(
                MAILMAN_CORE_ENDPOINT, l, DEFAULT_DOMAIN_NAME)
            response = requests.patch(patch_uri,
                                      patch_content,
                                      auth=(MAILMAN_CORE_USER,
                                            MAILMAN_CORE_PASSWORD))
            print("patching list {0} with template file {1}, result {2} {3}"
                  "".format(l, local_file, response.status_code,
                            response.text))
Beispiel #6
0
            ml = row[0].split('@')[0].strip()
            mailing = lists.setdefault(ml, {})
            to_add = mailing.setdefault('add', set())
            to_del = mailing.setdefault('delete', set())
            action = row[1].strip()
            if action == 'add':
                members = to_add
            else:
                members = to_del
            mail = row[2].strip()
            if '@' in mail:
                members.add(mail)

client = Client('http://localhost:8001/3.1', api_user, api_pass)
try:
    dom = client.get_domain(domain)
except (HTTPError, ) as exc:
    if exc.code != 404:
        raise
    dom = client.create_domain(domain)


def accept_request(ml, member):
    done = None
    for request in ml.requests:
        if request['email'] != member:
            continue
        if member not in [m.email for m in ml.members]:
            ml.accept_request(request['token'])
        else:
            ml.discard_request(request['token'])
class maillist(object):
    def __init__(self, **args):
        self.client = Client(args['rest_url'], args['rest_username'],
                             args['rest_password'])
        self.domain = self.client.get_domain(args['domain'])

        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)

    def get_lists(self):
        mailists = []
        for list in self.domain.lists:
            mailists.append(list.fqdn_listname)
        return mailists

    def create_list(self, **args):
        list = args['list']
        name = list.split('@')[0]
        self.logger.debug(list)
        self.logger.debug(name)
        self.domain.create_list(name)
        self.set_settings(list)

    def set_settings(self, list_fqdn):
        list = self.client.get_list(list_fqdn)
        for key, value in self.default_settings().items():
            list.settings[key] = value
        list.settings.save()

    def get_list_members(self, list_fqdn):
        members = []
        list = self.client.get_list(list_fqdn)
        for member in list.members:
            members.append(member.address.email.lower())
        return members

    def sync_members(self, list_fqdn, wannabe_members):
        members = self.get_list_members(list_fqdn)
        list = self.client.get_list(list_fqdn)

        todo_add = set(wannabe_members) - set(members)
        if len(todo_add) > 0:
            self.logger.info('Will add users to {}'.format(list_fqdn))
            self.logger.info(str(todo_add))

        todo_remove = set(members) - set(wannabe_members)
        if len(todo_remove) > 0:
            self.logger.info('Will remove users from {}'.format(list_fqdn))
            self.logger.info(str(todo_remove))
        for user in todo_remove:
            list.unsubscribe(user, pre_approved=True)
        for user in todo_add:
            list.subscribe(user,
                           pre_verified=True,
                           pre_confirmed=True,
                           pre_approved=True)

        return True

    def default_settings(self):
        return {
            "acceptable_aliases": [],
            "accept_these_nonmembers": [],
            "admin_immed_notify": True,
            "admin_notify_mchanges": False,
            "administrivia": False,
            "advertised": False,
            "allow_list_posts": True,
            "anonymous_list": False,
            "archive_policy": "private",
            "archive_rendering_mode": "text",
            "autorespond_owner": "none",
            "autorespond_postings": "none",
            "autorespond_requests": "none",
            "autoresponse_grace_period": "90d",
            "autoresponse_owner_text": "",
            "autoresponse_postings_text": "",
            "autoresponse_request_text": "",
            "bounce_info_stale_after": "7d",
            "bounce_notify_owner_on_disable": True,
            "bounce_notify_owner_on_removal": True,
            "bounce_score_threshold": 5,
            "bounce_you_are_disabled_warnings": 3,
            "bounce_you_are_disabled_warnings_interval": "7d",
            "collapse_alternatives": True,
            "convert_html_to_plaintext": False,
            "default_member_action": "defer",
            "default_nonmember_action": "hold",
            "description": "Wannabe list",
            "digest_send_periodic": False,
            "digest_size_threshold": 30.0,
            "digest_volume_frequency": "monthly",
            "digests_enabled": False,
            "discard_these_nonmembers": [],
            "dmarc_mitigate_action": "munge_from",
            "dmarc_mitigate_unconditionally": True,
            "dmarc_moderation_notice": "",
            "dmarc_wrapped_message_text": "",
            "emergency": False,
            "filter_action": "discard",
            "filter_content": False,
            "filter_extensions": [],
            "filter_types": [],
            "first_strip_reply_to": False,
            "forward_unrecognized_bounces_to": "administrators",
            "gateway_to_mail": False,
            "gateway_to_news": False,
            "hold_these_nonmembers": [],
            "include_rfc2369_headers": True,
            "info": "",
            "linked_newsgroup": "",
            "max_message_size": 128,
            "max_num_recipients": 12,
            "max_days_to_hold": 0,
            "member_roster_visibility": "moderators",
            "moderator_password": None,
            "newsgroup_moderation": "none",
            "nntp_prefix_subject_too": True,
            "pass_types": [],
            "pass_extensions": [],
            "personalize": "none",
            "posting_pipeline": "default-posting-pipeline",
            "preferred_language": "no",
            "process_bounces": True,
            "reject_these_nonmembers": [],
            "reply_goes_to_list": "no_munging",
            "reply_to_address": "",
            "require_explicit_destination": False,
            "respond_to_post_requests": True,
            "send_welcome_message": False,
            "subscription_policy": "moderate",
            "unsubscription_policy": "moderate",
            "usenet_watermark": None,
        }