def send_new_opportunity_email_to_sellers(brief_json, brief_url): to_email_addresses = [] if brief_json.get('sellerEmail'): to_email_addresses.append(brief_json['sellerEmail']) if brief_json.get('sellerEmailList'): to_email_addresses += brief_json['sellerEmailList'] if to_email_addresses: email_body = render_template( 'emails/seller_new_opportunity.html', brief=brief_json, brief_url=brief_url ) for to_email_address in to_email_addresses: # Send emails individually rather than sending to a list of emails try: send_email( to_email_address, email_body, current_app.config['SELLER_NEW_OPPORTUNITY_EMAIL_SUBJECT'], current_app.config['DM_GENERIC_NOREPLY_EMAIL'], current_app.config['DM_GENERIC_SUPPORT_NAME'], ) except EmailError as e: rollbar.report_exc_info() current_app.logger.error( 'seller new opportunity email failed to send. ' 'error {error}', extra={ 'error': six.text_type(e), }) abort(503, response='Failed to send seller new opportunity email.')
def test_serialize_and_send_payload(self, post=None): invalid_b64 = b'CuX2JKuXuLVtJ6l1s7DeeQ==' invalid = base64.b64decode(invalid_b64) def _raise(): # Make sure that the _invalid local variable makes its # way into the payload even if its value cannot be serialized # properly. _invalid = invalid # Make sure the Password field gets scrubbed even though its # original value could not be serialized properly. Password = invalid password = '******' raise Exception('bug bug') try: _raise() except: rollbar.report_exc_info() self.assertEqual(post.called, True) payload_data = post.call_args[1]['data'] self.assertIsInstance(payload_data, str) self.assertIn('bug bug', payload_data) try: json.loads(post.call_args[1]['data']) except: self.assertTrue(False)
def get_user_by_email(email): """Gets a User by `email` Returns None if not found """ from htk.apps.accounts.models import UserEmail if is_valid_email(email): # check for confirmed email addresses user_emails = UserEmail.objects.filter(email__iexact=email, is_confirmed=True) num_results = user_emails.count() if num_results == 1: user = user_emails[0].user elif num_results > 1: # there should only be one User with this email... # if there are more, we have a data error! raise NonUniqueEmail(email) else: # num_results == 0, so check UserModel for active users with email UserModel = get_user_model() try: user = UserModel.objects.get(email__iexact=email, is_active=True) except UserModel.MultipleObjectsReturned: user = None request = get_current_request() rollbar.report_exc_info() raise NonUniqueEmail(email) except UserModel.DoesNotExist: # also check newly registered accounts # if not user.is_active, handling will get passed downstream user = get_incomplete_signup_user_by_email(email) else: user = None return user
def update_locale_info_by_ip_from_request(self, request): """Update user info by IP Address Store last_login_ip only when logging in Store country resolved from IP Store timezone resolved from IP Caller: api.auth.decorators.register_or_login_user Unknown whether this code throws an exception, but catch it upstream if any """ try: ip = extract_request_ip(request) if ip and self.last_login_ip != ip: self.last_login_ip = ip try: from htk.lib.geoip.utils import get_country_code_by_ip from htk.lib.geoip.utils import get_timezone_by_ip detected_country = get_country_code_by_ip(ip) or '' detected_timezone = get_timezone_by_ip(ip) or '' self.detected_country = detected_country self.detected_timezone = detected_timezone except: # couldn't find geoip records for ip, just be quiet for now pass finally: self.save() except: # error extracting IP or saving rollbar.report_exc_info(request=request)
def test_scrub_self_referencing(self, send_payload): def _raise(obj): raise Exception() try: obj = {} obj['child'] = { 'parent': obj } # NOTE(cory): We copy the dict here so that we don't produce a circular reference # from the _rase() args. _raise(dict(obj)) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertTrue( (isinstance(payload['data']['body']['trace']['frames'][-1]['locals']['obj'], dict) and 'child' in payload['data']['body']['trace']['frames'][-1]['locals']['obj']) or (isinstance(payload['data']['body']['trace']['frames'][-1]['locals']['obj'], string_types) and payload['data']['body']['trace']['frames'][-1]['locals']['obj'].startswith('<CircularReference')) )
def division_lookup(): try: if request.json is None and request.method == 'POST': abort(400, "Must provide JSON (did you set Content-type?)") elif request.method == 'POST': args = request.json else: args = request.args if 'latitude' not in args: abort(400, "Most provide latitude and longitude") if 'longitude' not in args: abort(400, "Most provide latitude and longitude") conn = psycopg2.connect(host=dbcreds.HOSTNAME, database=dbcreds.DATABASE, user=dbcreds.USERNAME, password=dbcreds.PASSWORD) cursor = conn.cursor() cursor.execute(QUERY_FORMAT.format(latitude=float(args['latitude']), longitude=float(args['longitude']))) result = cursor.fetchone() if result is None: name = None else: name = result[0].lower().translate(None, " -'") return jsonify({'division': name}) except: rollbar.report_exc_info() raise
def crawl_by_url(cls, competition: Competition, url: str) -> int: count = 0 logger = CrawlerLogger.get_logger_for_class(cls) logger.log("crawl {}".format(competition.__str__())) try: tables = cls.get_tables(competition.get_league_url()) for table in tables: for row in table.findAll('tr'): try: if FSRLeagueParser.parse_row(row, competition): count = count + 1 except Exception as e: logger.error(e) rollbar.report_exc_info(sys.exc_info()) except Exception as e: logger.error(e) rollbar.report_exc_info(sys.exc_info()) # TODO: statistics # if lock: # with lock: # self.statistics['teams'] += count # else: # self.statistics['teams'] += count return count
def test_args_lambda_with_kwargs_and_args(self, send_payload): _raise = lambda arg1, arg2, **kwargs: foo(arg1) try: _raise('a1', 'a2', arg3='arg3-value', arg4=2) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) keywords = payload['data']['body']['trace']['frames'][-1]['keywordspec'] self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['argspec'])) self.assertEqual('arg1', payload['data']['body']['trace']['frames'][-1]['argspec'][0]) self.assertEqual('arg2', payload['data']['body']['trace']['frames'][-1]['argspec'][1]) self.assertEqual('a1', payload['data']['body']['trace']['frames'][-1]['locals']['arg1']) self.assertEqual('a2', payload['data']['body']['trace']['frames'][-1]['locals']['arg2']) self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][keywords])) self.assertEqual('arg3-value', payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['arg3']) self.assertEqual(2, payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['arg4'])
def test_args_lambda_with_kwargs_and_args_and_defaults(self, send_payload): _raise = lambda arg1, arg2, arg3='default-value', **kwargs: foo(arg1) try: _raise('a1', 'a2', arg3='arg3-value', arg4=2) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) keywords = payload['data']['body']['trace']['frames'][-1]['keywordspec'] # NOTE(cory): again, default values are strange for lambdas and we include them as # positional args. self.assertEqual(3, len(payload['data']['body']['trace']['frames'][-1]['argspec'])) self.assertEqual('arg1', payload['data']['body']['trace']['frames'][-1]['argspec'][0]) self.assertEqual('arg2', payload['data']['body']['trace']['frames'][-1]['argspec'][1]) self.assertEqual('arg3', payload['data']['body']['trace']['frames'][-1]['argspec'][2]) self.assertEqual('a1', payload['data']['body']['trace']['frames'][-1]['locals']['arg1']) self.assertEqual('a2', payload['data']['body']['trace']['frames'][-1]['locals']['arg2']) self.assertEqual('arg3-value', payload['data']['body']['trace']['frames'][-1]['locals']['arg3']) self.assertEqual(1, len(payload['data']['body']['trace']['frames'][-1]['locals'][keywords])) self.assertEqual(2, payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['arg4'])
def handle_event(event): """Processes a validated skill request from Amazon Alexa Returns a payload if applicable, else None """ event_handler = get_event_handler(event) if event_handler: try: payload = event_handler(event) except: payload = { 'version' : '1.0', 'response' : { 'outputSpeech' : { 'type' : 'SSML', 'ssml' : """<speak>Oops, I couldn't process that.</speak>""", } }, } rollbar.report_exc_info(extra_data={ 'event' : event, 'event_handler' : event_handler.__name__, }) else: payload = None return payload
def test_args_lambda_with_star_args_and_args(self, send_payload): _raise = lambda arg1, *args: foo(arg1) try: _raise('arg1-value', 1, 2) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) varargs = payload['data']['body']['trace']['frames'][-1]['varargspec'] self.assertEqual(1, len(payload['data']['body']['trace']['frames'][-1]['argspec'])) self.assertEqual('arg1', payload['data']['body']['trace']['frames'][-1]['argspec'][0]) self.assertEqual('arg1-value', payload['data']['body']['trace']['frames'][-1]['locals']['arg1']) self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][varargs])) self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][varargs][0], '\*+') self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][varargs][1], '\*+')
def application(environ, start_response): try: application = bottle.app() application.catchall = False application = JsonApiMiddleware(application) return application(environ, start_response) except: rollbar.report_exc_info(sys.exc_info(), webob.Request(environ)) # Bare bones 500 handler content = b"" if environ.get("JSON"): content = '{"__status_code__": 500}' content_type = "application/json; charset=UTF-8" else: dirname = os.path.dirname(__file__) five_hundred_path = os.path.join(dirname, "app/html/five_hundred.html") with open(five_hundred_path, "r", encoding="utf-8") as f: content = f.read() content_type = "text/html; charset=UTF-8" content = content.encode("utf-8") start_response( "500 Internal Server Error", [("Content-Type", content_type), ("Content-Length", str(len(content)))], sys.exc_info(), ) environ["wsgi.errors"] = content return [content]
def __call__(self, value): client = kickbox.Client(settings.KICKBOX_API_KEY) kickbox_client = client.kickbox() try: response = kickbox_client.verify(value) except ClientError as e: if e.code == 403 and e.message == 'Insufficient balance': rollbar.report_exc_info(sys.exc_info(), extra_data={'API': 'Kickbox', 'message': e.message}) # send notification notification = KickboxAPIInsuffinetBalanceNotification() EmailAdminsNotificationSender(notification=notification).notify() # and raise ValidationError to mark data as not valid raise InsufficientCreditsError('Kickbox: insufficient balance') raise ValidationError('Kickbox: %s' % e.message) except Exception as e: raise ValidationError('Kickbox: %s' % e.message) else: if response.body['result'] in ('risky', 'undeliverable'): raise ValidationError('Kickbox: email risky or undeliverable') elif response.body['role']: raise ValidationError('Kickbox: email is a role email') elif response.body['free']: raise ValidationError('Kickbox: email address uses free email service') elif response.body['disposable']: raise ValidationError('Kickbox: email address uses a disposable domain') elif response.body['result'] == 'unknown': reason = response.body['reason'] if reason == 'no_connect': raise ValidationError('Kickbox: unable to connect to the SMTP server') else: raise ValidationError('Kickbox: declined for reason "%s"' % reason) return True
def get_story_list(self, batch): """ get a list of stories corresponding to a list of hashes """ req_str = self.nb_endpoint + '/reader/starred_stories?' for a_hash in batch: req_str += 'h=' + a_hash + '&' stories = {} stories_req = requests.Request('GET', req_str, cookies=self.cookies) try: stories = self.request_with_backoff(stories_req) except requests.exceptions.ConnectionError as e: rollbar.report_exc_info() msg = 'Failed to get stories' logger.error(msg) logger.debug('Request string: %s', req_str) logger.error(e) statsd.event(msg, e.message, alert_type='error') logger.debug(stories.text) statsd.increment('nb.http_requests.get') story_list = [] try: story_list = json.loads(stories.text)['stories'] except ValueError as e: rollbar.report_exc_info() msg = 'Failed to parse stories response' logger.error(msg) logger.error(e) statsd.event(msg, e.message, alert_type='error') logger.debug(stories.text) return story_list
def handle_error(request, exception, exc_info): if( isinstance(exception, EXCEPTION_BLACKLIST) and not isinstance(exception, EXCEPTION_WHITELIST) ): return rollbar.report_exc_info(exc_info, request)
def test_args_generators(self, send_payload): def _raise(arg1): for i in range(2): if i > 0: raise Exception() else: yield i try: l = list(_raise('hello world')) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) self.assertEqual(1, len(payload['data']['body']['trace']['frames'][-1]['argspec'])) self.assertEqual('arg1', payload['data']['body']['trace']['frames'][-1]['argspec'][0]) self.assertEqual('hello world', payload['data']['body']['trace']['frames'][-1]['locals']['arg1'])
def upload(url, root, env=None, **kwargs): try: if not root: root = os.getcwd() args = dict(commit='', branch='', job='') args.update(kwargs) assert args.get('branch') not in ('', None), "branch is required" assert args.get('commit') not in ('', None), "commit hash is required" assert any((args.get('job'), (args.get('build') and args.get('service') == 'circleci'), args.get('token'))), "missing token or other required argument(s)" reports = build_reports(root) if env: reports = "\n<<<<<< ENV\n".join(("\n".join(["%s=%s" % (k, os.getenv(k, '')) for k in env]), reports)) kwargs['package'] = "codecov-v%s" % VERSION url = "%s/upload/v2?%s" % (url, urlencode(dict([(k, v.strip()) for k, v in kwargs.items() if v is not None]))) result = requests.post(url, data=reports) if result.status_code != 200: sys.stdout.write(result.text) result.raise_for_status() return result.json() except AssertionError as e: rollbar.report_exc_info() return dict(message=str(e), uploaded=False, coverage=0)
def test_anonymous_tuple_args(self, send_payload): # Only run this test on Python versions that support it if not _anonymous_tuple_func: return try: _anonymous_tuple_func((1, (2, 3), 4)) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) self.assertEqual(4, len(payload['data']['body']['trace']['frames'][-1]['argspec'])) self.assertEqual(1, payload['data']['body']['trace']['frames'][-1]['argspec'][0]) self.assertEqual(2, payload['data']['body']['trace']['frames'][-1]['argspec'][1]) self.assertEqual(3, payload['data']['body']['trace']['frames'][-1]['argspec'][2]) self.assertEqual(4, payload['data']['body']['trace']['frames'][-1]['argspec'][3]) self.assertEqual(10, payload['data']['body']['trace']['frames'][-1]['locals']['ret'])
def send_activation_email(self, domain=None, resend=False, template=None, subject=None, sender=None): """Sends an activation email """ domain = domain or htk_setting('HTK_DEFAULT_EMAIL_SENDING_DOMAIN') self._reset_activation_key(resend=resend) try: should_send_activation_email = True if htk_setting('HTK_ITERABLE_ENABLED'): from htk.lib.iterable.utils import get_iterable_api_client from htk.lib.iterable.utils import get_campaign_id if resend: campaign_key = 'triggered.transactional.account.confirm_email_resend' else: campaign_key = 'triggered.transactional.account.sign_up_confirm_email' itbl_campaign_id = get_campaign_id(campaign_key) if itbl_campaign_id: should_send_activation_email = False data = { 'activation_uri' : self.get_activation_uri(domain=domain), } itbl = get_iterable_api_client() itbl.send_triggered_email(self.email, itbl_campaign_id, data=data) if should_send_activation_email: activation_email(self, domain=domain, template=template, subject=subject, sender=sender) except: request = get_current_request() rollbar.report_exc_info(request=request)
def test_dont_scrub_star_args(self, send_payload): rollbar.SETTINGS['locals']['scrub_varargs'] = False def _raise(*args): raise Exception() try: _raise('sensitive', 'text') except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertNotIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('locals', payload['data']['body']['trace']['frames'][-1]) varargspec = payload['data']['body']['trace']['frames'][-1]['varargspec'] self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][varargspec])) self.assertEqual(payload['data']['body']['trace']['frames'][-1]['locals'][varargspec][0], 'sensitive') self.assertEqual(payload['data']['body']['trace']['frames'][-1]['locals'][varargspec][1], 'text')
def store_ballot(): try: if request.json is not None: division = request.json["division"] division_ticket = request.json["division_ticket"] senate_ticket = request.json["senate_ticket"] order_by_group = request.json["order_by_group"] else: division = request.form["division"] division_ticket = request.form["division_ticket"].split(",") senate_ticket = request.form["senate_ticket"].split(",") order_by_group = bool(int(request.form["order_by_group"])) ballot_id = store_at_random_id( { "division": division, "division_ticket": ",".join(str(x) for x in division_ticket), "senate_ticket": ",".join(str(x) for x in senate_ticket), "order_by_group": int(order_by_group), } ) return jsonify({"ballot_id": ballot_id}) except: rollbar.report_exc_info() raise
def test_scrub_kwargs(self, send_payload): def _raise(**kwargs): raise Exception() try: _raise(password='******', clear='text') except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertNotIn('argspec', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('varargspec', payload['data']['body']['trace']['frames'][-1]) self.assertIn('keywordspec', payload['data']['body']['trace']['frames'][-1]) keywords = payload['data']['body']['trace']['frames'][-1]['keywordspec'] self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][keywords])) self.assertIn('password', payload['data']['body']['trace']['frames'][-1]['locals'][keywords]) self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['password'], '\*+') self.assertIn('clear', payload['data']['body']['trace']['frames'][-1]['locals'][keywords]) self.assertEqual('text', payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['clear'])
def test_scrub_locals(self, send_payload): invalid_b64 = b'CuX2JKuXuLVtJ6l1s7DeeQ==' invalid = base64.b64decode(invalid_b64) def _raise(): # Make sure that the _invalid local variable makes its # way into the payload even if its value cannot be serialized # properly. _invalid = invalid # Make sure the Password field gets scrubbed even though its # original value could not be serialized properly. Password = invalid password = '******' raise Exception((_invalid, Password, password)) try: _raise() except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['password'], '\*+') self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['Password'], '\*+') self.assertIn('_invalid', payload['data']['body']['trace']['frames'][-1]['locals']) binary_type_name = 'str' if python_major_version() < 3 else 'bytes' undecodable_message = '<Undecodable type:(%s) base64:(%s)>' % (binary_type_name, base64.b64encode(invalid).decode('ascii')) self.assertEqual(undecodable_message, payload['data']['body']['trace']['frames'][-1]['locals']['_invalid'])
def check_uuids(): num_changed = 0 offset = cache.get(COUNTER_CACHE_NAME) or 0 players = _get_players(offset) if not players: rollbar.report_message('All players checked, check_uuids wrapping around', level='info', extra_data={ 'offset': offset }) offset = 0 players = _get_players(offset) for player in players: try: changed = _handle_player(player) except (IntegrityError, OperationalError): db.session.rollback() rollbar.report_exc_info(level='warning', extra_data={ 'uuid': player.uuid }) else: if changed: num_changed += 1 cache.set(COUNTER_CACHE_NAME, offset + PLAYERS_PER_JOB, 86400) rollbar.report_message('Finished checking uuid group', level='info', extra_data={ 'offset': offset, 'num_changed': num_changed })
def test_long_list_arg_val(self, send_payload): def _raise(large): raise Exception() try: xlarge = ['hi' for _ in range(30)] # NOTE(cory): We copy the list here so that the local variables from # this frame are not referenced directly by the frame from _raise() # call above. If we didn't copy this list, Rollbar would report a # circular reference for the args on _raise(). _raise([str(x) for x in xlarge]) except: rollbar.report_exc_info() self.assertEqual(send_payload.called, True) payload = json.loads(send_payload.call_args[0][0]) self.assertIn('args', payload['data']['body']['trace']['frames'][-1]) self.assertNotIn('kwargs', payload['data']['body']['trace']['frames'][-1]) self.assertEqual(1, len(payload['data']['body']['trace']['frames'][-1]['args'])) self.assertTrue( ("['hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', ...]" == payload['data']['body']['trace']['frames'][-1]['args'][0]) or ("['hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', ...]" == payload['data']['body']['trace']['frames'][0]['locals']['xlarge']))
def api_call(server, type, data=None): api = get_api(server.address) try: if data: result = api.call(type, data) else: result = api.call(type) except Exception: rollbar.report_exc_info( extra_data={ 'server_id': server.id, 'type': type, 'data': data } ) return None if not result or result.get('result') == API_CALL_RESULTS['exception']: extra_data = { 'server_id': server.id, 'data': data } if result: extra_data['message'] = result.get('message') else: extra_data['message'] = 'No result!' rollbar.report_message('Exception while calling server API', level='error', extra_data=extra_data) return None return result
def emit(self, record): if record.exc_info: rollbar.report_exc_info(record.exc_info) else: request = None rollbar.report_message(record.msg, record.levelname, request=request)
def report_error(): data = {'version': plugin.addon.getAddonInfo('version'), 'platform': platform.system(), 'machine': platform.machine(), 'url': plugin.request.url, 'kodi': kodi_version()} rollbar.report_exc_info(extra_data=data)
def execute_wrapper(self, query_str, query_params=None): cursor = self.conn.cursor() try: cursor.execute(query_str, query_params) except MySQLError: rollbar.report_exc_info() return cursor
def create_campaign(client, recipients, settings=None): if settings is None: settings = {} settings.update({ 'from_name': 'The Marketplace team', 'reply_to': current_app.config.get('GENERIC_CONTACT_EMAIL') }) try: response = client.campaigns.create( data={ 'type': 'regular', 'recipients': recipients, 'settings': settings } ) current_app.logger.info('Mailchimp campaign {} created with list {}' .format(response['id'], recipients['list_id'])) return response except RequestException as e: current_app.logger.error( 'A Mailchimp API error occurred while creating a campaign, aborting: {} {}'.format(e, e.response)) rollbar.report_exc_info() raise e