diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound')
10 files changed, 731 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/__init__.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/__init__.py new file mode 100644 index 00000000..85ab4d0b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/__init__.py @@ -0,0 +1,13 @@ +""" +Inbound Parse helper +-------------------- +This is a standalone module to help get you started consuming and processing +Inbound Parse data. It provides a Flask server to listen for Inbound Parse +POSTS, and utilities to send sample data to the server. + +See README.txt for detailed usage instructions, including quick-start guides +for local testing and Heroku deployment. +""" + +from .config import * # noqa +from .parse import * # noqa diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/app.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/app.py new file mode 100644 index 00000000..0d443590 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/app.py @@ -0,0 +1,45 @@ +"""Receiver module for processing SendGrid Inbound Parse messages. + +See README.txt for usage instructions.""" +try: + from config import Config +except: + # Python 3+, Travis + from sendgrid.helpers.inbound.config import Config + +try: + from parse import Parse +except: + # Python 3+, Travis + from sendgrid.helpers.inbound.parse import Parse + +from flask import Flask, request, render_template +import os + +app = Flask(__name__) +config = Config() + + +@app.route('/', methods=['GET']) +def index(): + """Show index page to confirm that server is running.""" + return render_template('index.html') + + +@app.route(config.endpoint, methods=['POST']) +def inbound_parse(): + """Process POST from Inbound Parse and print received data.""" + parse = Parse(config, request) + # Sample processing action + print(parse.key_values()) + # Tell SendGrid's Inbound Parse to stop sending POSTs + # Everything is 200 OK :) + return "OK" + + +if __name__ == '__main__': + # Be sure to set config.debug_mode to False in production + port = int(os.environ.get("PORT", config.port)) + if port != config.port: + config.debug = False + app.run(host='0.0.0.0', debug=config.debug_mode, port=port) diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.py new file mode 100644 index 00000000..06ca683c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.py @@ -0,0 +1,65 @@ +"""Set up credentials (.env) and application variables (config.yml)""" +import os +import yaml + + +class Config(object): + """All configuration for this app is loaded here""" + + def __init__(self, **opts): + if os.environ.get('ENV') != 'prod': # We are not in Heroku + self.init_environment() + + """Allow variables assigned in config.yml available the following variables + via properties""" + self.path = opts.get( + 'path', os.path.abspath(os.path.dirname(__file__)) + ) + with open('{0}/config.yml'.format(self.path)) as stream: + config = yaml.load(stream, Loader=yaml.FullLoader) + self._debug_mode = config['debug_mode'] + self._endpoint = config['endpoint'] + self._host = config['host'] + self._keys = config['keys'] + self._port = config['port'] + + @staticmethod + def init_environment(): + """Allow variables assigned in .env available using + os.environ.get('VAR_NAME')""" + base_path = os.path.abspath(os.path.dirname(__file__)) + env_path = '{0}/.env'.format(base_path) + if os.path.exists(env_path): + with open(env_path) as f: + lines = f.readlines() + for line in lines: + var = line.strip().split('=') + if len(var) == 2: + os.environ[var[0]] = var[1] + + @property + def debug_mode(self): + """Flask debug mode - set to False in production.""" + return self._debug_mode + + @property + def endpoint(self): + """Endpoint to receive Inbound Parse POSTs.""" + return self._endpoint + + @property + def host(self): + """URL that the sender will POST to.""" + return self._host + + @property + def keys(self): + """Incoming Parse fields to parse. For reference, see + https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html + """ + return self._keys + + @property + def port(self): + """Port to listen on.""" + return self._port diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.yml b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.yml new file mode 100644 index 00000000..d1a131ae --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/config.yml @@ -0,0 +1,34 @@ +# Incoming Parse endpoint +endpoint: '/inbound' + +# Port to listen on +port: 5000 + +# Flask debug mode +# Set this to False in production +# Reference: http://flask.pocoo.org/docs/0.11/api/#flask.Flask.run +debug_mode: True + +# List all Incoming Parse fields you would like parsed +# Reference: https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html +keys: + - from + - attachments + - headers + - text + - envelope + - to + - html + - sender_ip + - attachment-info + - subject + - dkim + - SPF + - charsets + - content-ids + - spam_report + - spam_score + - email + +# URL that the sender will POST to +host: 'http://127.0.0.1:5000/inbound' diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/parse.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/parse.py new file mode 100644 index 00000000..49627a12 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/parse.py @@ -0,0 +1,100 @@ +"""Parse data received from the SendGrid Inbound Parse webhook""" +import base64 +import email +import mimetypes +from six import iteritems +from werkzeug.utils import secure_filename + + +class Parse(object): + + def __init__(self, config, request): + self._keys = config.keys + self._request = request + request.get_data(as_text=True) + self._payload = request.form + self._raw_payload = request.data + + def key_values(self): + """ + Return a dictionary of key/values in the payload received from + the webhook + """ + key_values = {} + for key in self.keys: + if key in self.payload: + key_values[key] = self.payload[key] + return key_values + + def get_raw_email(self): + """ + This only applies to raw payloads: + https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Raw-Parameters + """ + if 'email' in self.payload: + raw_email = email.message_from_string(self.payload['email']) + return raw_email + else: + return None + + def attachments(self): + """Returns an object with: + type = file content type + file_name = the name of the file + contents = base64 encoded file contents""" + attachments = None + if 'attachment-info' in self.payload: + attachments = self._get_attachments(self.request) + # Check if we have a raw message + raw_email = self.get_raw_email() + if raw_email is not None: + attachments = self._get_attachments_raw(raw_email) + return attachments + + def _get_attachments(self, request): + attachments = [] + for _, filestorage in iteritems(request.files): + attachment = {} + if filestorage.filename not in (None, 'fdopen', '<fdopen>'): + filename = secure_filename(filestorage.filename) + attachment['type'] = filestorage.content_type + attachment['file_name'] = filename + attachment['contents'] = base64.b64encode(filestorage.read()) + attachments.append(attachment) + return attachments + + def _get_attachments_raw(self, raw_email): + attachments = [] + counter = 1 + for part in raw_email.walk(): + attachment = {} + if part.get_content_maintype() == 'multipart': + continue + filename = part.get_filename() + if not filename: + ext = mimetypes.guess_extension(part.get_content_type()) + if not ext: + ext = '.bin' + filename = 'part-%03d%s' % (counter, ext) + counter += 1 + attachment['type'] = part.get_content_type() + attachment['file_name'] = filename + attachment['contents'] = part.get_payload(decode=False) + attachments.append(attachment) + return attachments + + @property + def keys(self): + return self._keys + + @property + def request(self): + return self._request + + @property + def payload(self): + return self._payload + + @property + def raw_payload(self): + return self._raw_payload diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data.txt b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data.txt new file mode 100644 index 00000000..7c3ce6be --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data.txt @@ -0,0 +1,58 @@ +--xYzZY +Content-Disposition: form-data; name="headers" + +MIME-Version: 1.0 +Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 18:10:13 -0700 (PDT) +From: Example User <test@example.com> +Date: Wed, 10 Aug 2016 18:10:13 -0700 +Subject: Inbound Parse Test Data +To: inbound@inbound.example.com +Content-Type: multipart/alternative; boundary=001a113df448cad2d00539c16e89 + +--xYzZY +Content-Disposition: form-data; name="dkim" + +{@sendgrid.com : pass} +--xYzZY +Content-Disposition: form-data; name="to" + +inbound@inbound.example.com +--xYzZY +Content-Disposition: form-data; name="html" + +<html><body><strong>Hello Twilio SendGrid!</body></html> + +--xYzZY +Content-Disposition: form-data; name="from" + +Example User <test@example.com> +--xYzZY +Content-Disposition: form-data; name="text" + +Hello Twilio SendGrid! + +--xYzZY +Content-Disposition: form-data; name="sender_ip" + +0.0.0.0 +--xYzZY +Content-Disposition: form-data; name="envelope" + +{"to":["inbound@inbound.example.com"],"from":"test@example.com"} +--xYzZY +Content-Disposition: form-data; name="attachments" + +0 +--xYzZY +Content-Disposition: form-data; name="subject" + +Testing non-raw +--xYzZY +Content-Disposition: form-data; name="charsets" + +{"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"} +--xYzZY +Content-Disposition: form-data; name="SPF" + +pass +--xYzZY--
\ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data_with_attachments.txt b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data_with_attachments.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/default_data_with_attachments.txt diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data.txt b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data.txt new file mode 100644 index 00000000..12f64cb4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data.txt @@ -0,0 +1,57 @@ +--xYzZY +Content-Disposition: form-data; name="dkim" + +{@sendgrid.com : pass} +--xYzZY +Content-Disposition: form-data; name="email" + +MIME-Version: 1.0 +Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 14:44:21 -0700 (PDT) +From: Example User <test@example.com> +Date: Wed, 10 Aug 2016 14:44:21 -0700 +Subject: Inbound Parse Test Raw Data +To: inbound@inbound.inbound.com +Content-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a + +--001a113ee97c89842f0539be8e7a +Content-Type: text/plain; charset=UTF-8 + +Hello Twilio SendGrid! + +--001a113ee97c89842f0539be8e7a +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +<html><body><strong>Hello Twilio SendGrid!</body></html> + +--001a113ee97c89842f0539be8e7a-- + +--xYzZY +Content-Disposition: form-data; name="to" + +inbound@inbound.inbound.com +--xYzZY +Content-Disposition: form-data; name="from" + +Example User <test@example.com> +--xYzZY +Content-Disposition: form-data; name="sender_ip" + +0.0.0.0 +--xYzZY +Content-Disposition: form-data; name="envelope" + +{"to":["inbound@inbound.inbound.com"],"from":"test@example.com"} +--xYzZY +Content-Disposition: form-data; name="subject" + +Testing with Request.bin +--xYzZY +Content-Disposition: form-data; name="charsets" + +{"to":"UTF-8","subject":"UTF-8","from":"UTF-8"} +--xYzZY +Content-Disposition: form-data; name="SPF" + +pass +--xYzZY--
\ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt new file mode 100644 index 00000000..058fd8a6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt @@ -0,0 +1,298 @@ +--xYzZY +Content-Disposition: form-data; name="dkim" + +{@sendgrid.com : pass} +--xYzZY +Content-Disposition: form-data; name="email" + +MIME-Version: 1.0 +Received: by 0.0.0.0 with HTTP; Mon, 15 Aug 2016 13:47:21 -0700 (PDT) +From: Example User <test@example.com> +Date: Mon, 15 Aug 2016 13:47:21 -0700 +Subject: Inbound Parse Test Raw Data with Attachment +To: inbound@inbound.inbound.com +Content-Type: multipart/mixed; boundary=001a1140ffb6f4fc63053a2257e2 + +--001a1140ffb6f4fc63053a2257e2 +Content-Type: multipart/alternative; boundary=001a1140ffb6f4fc5f053a2257e0 + +--001a1140ffb6f4fc5f053a2257e0 +Content-Type: text/plain; charset=UTF-8 + +Hello Twilio SendGrid! + +--001a1140ffb6f4fc5f053a2257e0 +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +<html><body><strong>Hello Twilio SendGrid!</body></html> + +--001a1140ffb6f4fc5f053a2257e0-- + +--001a1140ffb6f4fc63053a2257e2 +Content-Type: image/jpeg; name="SendGrid.jpg" +Content-Disposition: attachment; filename="SendGrid.jpg" +Content-Transfer-Encoding: base64 +X-Attachment-Id: f_irwihell0 + +/9j/4AAQSkZJRgABAQABLAEsAAD/4QDKRXhpZgAATU0AKgAAAAgABwESAAMA +AAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAEx +AAIAAAARAAAAcgEyAAIAAAAUAAAAhIdpAAQAAAABAAAAmAAAAAAAAAEsAAAA +AQAAASwAAAABUGl4ZWxtYXRvciAzLjQuNAAAMjAxNjowODoxMSAxNjowODo1 +NwAAA6ABAAMAAAABAAEAAKACAAQAAAABAAACEqADAAQAAAABAAACFQAAAAD/ +4Qn2aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVn +aW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4 +bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAg +Q29yZSA1LjQuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53 +My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3Jp +cHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2Jl +LmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9l +bGVtZW50cy8xLjEvIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxNi0wOC0xMVQxNjow +ODo1NyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBJbWFnZVJlYWR5Ij4gPGRj +OnN1YmplY3Q+IDxyZGY6QmFnLz4gPC9kYzpzdWJqZWN0PiA8L3JkZjpEZXNj +cmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+AP/tADhQaG90b3Nob3Ag +My4wADhCSU0EBAAAAAAAADhCSU0EJQAAAAAAENQdjNmPALIE6YAJmOz4Qn7/ +wAARCAIVAhIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQF +BgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJx +FDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdI +SUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKj +pKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx +8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QA +tREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB +CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldY +WVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmq +srO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6 +/9sAQwAcHBwcHBwwHBwwRDAwMERcRERERFx0XFxcXFx0jHR0dHR0dIyMjIyM +jIyMqKioqKioxMTExMTc3Nzc3Nzc3Nzc/9sAQwEiJCQ4NDhgNDRg5pyAnObm +5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm +5ubm/90ABAAi/9oADAMBAAIRAxEAPwDpKKKKACiiigAooooAKKKKACiiigAo +oooAKKKKACiiigAooooAKKKKACiiigDEnkkEzgMep71F5sn94/nTp/8AXP8A +U1FXWloeZJu7H+bJ/eP50ebJ/eP50yinYm7H+bJ/eP50ebJ/eP50yiiwXY/z +ZP7x/OjzZP7x/OmUUWC7H+bJ/eP50ebJ/eP50yiiwXY/zZP7x/OjzZP7x/Om +UUWC7H+bJ/eP50ebJ/eP50yiiwXY/wA2T+8fzo82T+8fzplFFgux/myf3j+d +Hmyf3j+dMoosF2P82T+8fzo82T+8fzplFFgux/myf3j+dHmyf3j+dMoosF2I +0sufvt+dJ5sv99vzNMbrSVVkbpuxJ5sv99vzNHmy/wB9vzNR0U7Id2SebL/f +b8zR5sv99vzNR0UWQXZJ5sv99vzNHmy/32/M1HRRZBdknmy/32/M0ebL/fb8 +zUdFFkF2SebL/fb8zR5sv99vzNR0UWQXZJ5sv99vzNHmy/32/M1HRRZBdknm +y/32/M0ebL/fb8zUdFFkF2SebL/fb8zR5sv99vzNR0UWQXZJ5sv99vzNHmy/ +32/M1HRRZBdknmy/32/M0ebL/fb8zUdFFkF2SebL/fb8zR5sv99vzNR0UWQX +Z//Q6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo +oooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKACiiigAooooAKK +KKACiiigAooooAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiigAooooAKKKKAC +iiigAooooAKKKKACiiigAooooAKKKKACiiigD//R6SiiigAooooAKKKKACii +igAooooAKKKKACiiigAooooAKKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKu +xbHly3YUUUUyQooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig +CJutJSt1pKo3WwUUUUDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigD//S6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA +KKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKAC +iiigAooooAKKKKACiiigAooooAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiig +AooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD//T6SiiigAo +oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAwZ/9c/1N +RVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiigAooooAKKKKACiiigAooooAKK +KKACiiigAooooAKKKKACiiigD//U6SiiigAooooAKKKKACiiigAooooAKKKK +ACiiigAooooAKKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUy +QooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCJutJSt1pKo3 +WwUUUUDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig +D//V6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo +oooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKACiiigAooooAKK +KKACiiigAooooAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiigAooooAKKKKAC +iiigAooooAKKKKACiiigAooooAKKKKACiiigD//W6SiiigAooooAKKKKACii +igAooooAKKKKACiiigAooooAKKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKu +xbHly3YUUUUyQooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig +CJutJSt1pKo3WwUUUUDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigD//X6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA +KKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKAC +iiigAooooAKKKKACiiigAooooAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiig +AooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD//Q6SiiigAo +oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAwZ/9c/1N +RVLP/rn+pqKuxbHly3YUUUUyQooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigCJutJSt1pKo3WwUUUUDCiiigAooooAKKKKACiiigAooooAKK +KKACiiigAooooAKKKKACiiigD//R6SiiigAooooAKKKKACiiigAooooAKKKK +ACiiigAooooAKKKKACiiigAooooAwZ/9c/1NRVLP/rn+pqKuxbHly3YUUUUy +QooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCJutJSt1pKo3 +WwUUUUDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig +D//S2i7560m9/WmnqaStbHPdj97+tG9/WmUUWC7H739aN7+tMoosF2P3v60b +39aZRRYLsfvf1o3v60yiiwXY/e/rRvf1plFFgux+9/Wje/rTKKLBdj97+tG9 +/WmUUWC7H739aN7+tMoosF2P3v60b39aZRRYLsfvf1o3v60yiiwXZlzEmVvr +UeTT5f8AWt9ajrdbHI9xcmjJpKKYhcmjJpKKAFyaMmkooAXJoyaSigBcmjJp +KKAFyaMmkooAXJoyaSigBcmjJpKKAFyaMmkooAXJoyaSigBwAPWlwKB0paBX +YmBRgUtFAXYmBRgUtFAXYmBRgUtFAXYmBRgUtFAXYmBRgUtFAXYmBRgUtFAX +YmBRgUtFAXYmBRgUtFAXYmBRgUtFAXYmBRgUtFAXYmBRgUtFAXZ//9PXPU0l +KeppK1OYKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK +AMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFF +FABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACiiigAooooAKKKKACiiigAoooo +AKKKKACiiigAooooAKKKKACiiigD/9TXPU0lKeppK1OYKKKKACiiigAooooA +KKKKACiiigAooooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyv +cKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQ +dKWgkKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACi +iigD/9XXPU0lKeppK1OYKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii +igAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABR +RRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACiiigAooooAKKK +KACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9bXPU0lKeppK1OYKKKK +ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqS +X/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUU +AFFFFADx0paQdKWgkKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA +ooooAKKKKACiiigD/9fXPU0lKeppK1OYKKKKACiiigAooooAKKKKACiiigAo +oooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQA +UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACi +iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9DXPU0l +KeppK1OYKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK +AMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFF +FABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACiiigAooooAKKKKACiiigAoooo +AKKKKACiiigAooooAKKKKACiiigD/9HXPU0lKeppK1OYKKKKACiiigAooooA +KKKKACiiigAooooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyv +cKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQ +dKWgkKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACi +iigD/9LXPU0lKeppK1OYKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii +igAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABR +RRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACiiigAooooAKKK +KACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9PXPU0lKeppK1OYKKKK +ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqS +X/Wt9ajroRyvcKKKKBBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUU +AFFFFADx0paQdKWgkKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA +ooooAKKKKACiiigD/9TXPU0lKeppK1OYKKKKACiiigAooooAKKKKACiiigAo +oooAKKKKACiiigAooooAKKKKAMqX/Wt9ajqSX/Wt9ajroRyvcKKKKBBRRRQA +UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFADx0paQdKWgkKKKKACi +iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9WV7mUO +Rnv6U37TN6/pUMn32+pptdyiuxxNssfaZvX9KPtM3r+lV6KOVdguyx9pm9f0 +o+0zev6VXoo5V2C7LH2mb1/Sj7TN6/pVeijlXYLssfaZvX9KPtM3r+lV6KOV +dguyx9pm9f0o+0zev6VXoo5V2C7LH2mb1/Sj7TN6/pVeijlXYLssfaZvX9KP +tM3r+lV6KOVdguyx9pm9f0o+0zev6VXoo5V2C7LH2mb1/Sj7TN6/pVeijlXY +LssfaZvX9KPtM3r+lV6KOVdguzRSFJFEjdTyad9mi96fD/ql+lS1g27lcqK/ +2aL3o+zRe9WKKXMw5V2K/wBmi96Ps0XvViijmYcq7Ff7NF70fZoverFFHMw5 +V2K/2aL3o+zRe9WKKOZhyrsV/s0XvR9mi96sUUczDlXYr/Zovej7NF71Yoo5 +mHKuxX+zRe9H2aL3qxRRzMOVdiv9mi96Ps0XvViijmYcq7Ff7NF70fZoverF +FHMw5V2K/wBmi96Ps0XvViijmYcq7BHZwlcnP50/7FB6H86ni+4KkqHJ9zdU +422Kn2KD0P50fYoPQ/nVuilzvuP2cexU+xQeh/Oj7FB6H86t0Uc77h7OPYqf +YoPQ/nR9ig9D+dW6KOd9w9nHsVPsUHofzo+xQeh/OrdFHO+4ezj2Kn2KD0P5 +0fYoPQ/nVuijnfcPZx7FT7FB6H86PsUHofzq3RRzvuHs49ip9ig9D+dH2KD0 +P51boo533D2cexU+xQeh/Oj7FB6H86t0Uc77h7OPYqfYoPQ/nR9ig9D+dW6K +Od9w9nHsVPsUHofzo+xQeh/OrdFHO+4ezj2Kn2KD0P50fYoPQ/nVuijnfcPZ +x7H/1mSffb6mm06T77fU02u9HCwooooAKKKKACiiigAooooAKKKKACiiigAo +oooAKKKKACiiigAooooA1of9Uv0qWoof9Uv0qWuZ7mqCiiikAUUUUAFFFFAB +RRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBai+4KkqOL7gqSs3udEdgooo +pDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9dk +n32+pptOk++31NNrvRwsKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii +igAooooAKKKKANaH/VL9KlqKH/VL9Klrme5qgooopAFFFFABRRRQAUUUUAFF +FFABRRRQAUUUUAFFFFABRRRQAUUUUAWovuCpKji+4KkrN7nRHYKKKKQwoooo +AKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//QZJ99vqab +TpPvt9TTa70cLCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK +ACiiigDWh/1S/Spaih/1S/Spa5nuaoKKKKQBRRRQAUUUUAFFFFABRRRQAUUU +UAFFFFABRRRQAUUUUAFFFFAFqL7gqSo4vuCpKze50R2CiiikMKKKKACiiigA +ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/0WSffb6mm06T77fU +02u9HCwooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA +1of9Uv0qWoof9Uv0qWuZ7mqCiiikAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQ +AUUUUAFFFFABRRRQBai+4KkqOL7gqSs3udEdgooopDCiiigAooooAKKKKACi +iigAooooAKKKKACiiigAooooAKKKKACiiigD/9Jkn32+pptOk++31NNrvRws +KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKANaH/VL9 +KlqKH/VL9Klrme5qgooopAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAB +RRRQAUUUUAWovuCpKji+4KkrN7nRHYKKKKQwooooAKKKKACiiigAooooAKKK +KACiiigAooooAKKKKACiiigAooooA//TZJ99vqabTpPvt9TTa70cLCiiigAo +oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDWh/1S/Spaih/1 +S/Spa5nuaoKKKKQBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF +FFAFqL7gqSo4vuCpKze50R2CiiikMKKKKACiiigAooooAKKKKACiiigAoooo +AKKKKACiiigAooooAKKKKAP/1GSffb6mm06T77fU02u9HCwooooAKKKKACii +igAooooAKKKKACiiigAooooAKKKKACiiigAooooA1of9Uv0qWoof9Uv0qWuZ +7mqCiiikAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBai+ +4KkqOL7gqSs3udEdgooopDCiiigAooooAKKKKACiiigAooooAKKKKACiiigA +ooooAKKKKACiiigD/9Vkn32+pptOk++31NNrvRwsKKKKACiiigAooooAKKKK +ACiiigAooooAKKKKACiiigAooooAKKKKANaH/VL9KlqKH/VL9Klrme5qgooo +pAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAWovuCpKji+ +4KkrN7nRHYKKKKQwooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACi +iigAooooA//WZJ99vqabTpPvt9TTa70cLCiiigAooooAKKKKACiiigAooooA +KKKKACiiigAooooAKKKKACiiigDWh/1S/Spaih/1S/Spa5nuaoKKKKQBRRRQ +AUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFqL7gqSo4vuCpKze5 +0R2CiiikMKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK +KAP/12Sffb6mm06T77fU02u9HCwooooAKKKKACiiigAooooAKKKKACiiigAo +oooAKKKKACiiigAooooA1of9Uv0qWoof9Uv0qWuZ7mqCiiikAUUUUAFFFFAB +RRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBai+4KkqOL7gqSs3udEdgooo +pDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9DU +OnxMSdx5pP7Oi/vNWjRV+0l3I5I9jO/s6L+81H9nRf3mrRoo9pLuHs49jO/s +6L+81H9nRf3mrRoo9pLuHs49jO/s6L+81H9nRf3mrRoo9pLuHs49jO/s6L+8 +1H9nRf3mrRoo9pLuHs49jO/s6L+81H9nRf3mrRoo9pLuHs49jO/s6L+81H9n +Rf3mrRoo9pLuHs49jO/s6L+81H9nRf3mrRoo9pLuHs49jO/s6L+81H9nRf3m +rRoo9pLuHs49jO/s6L+81H9nRf3mrRoo9pLuHs49jO/s6L+81H9nRf3mrRoo +9pLuHs49iBLdUUKCeKd5K+pqWip5mPlRF5K+po8lfU1LRRdhyoi8lfU0eSvq +aloouw5UReSvqaPJX1NS0UXYcqIvJX1NHkr6mpaKLsOVEXkr6mjyV9TUtFF2 +HKiLyV9TR5K+pqWii7DlRF5K+po8lfU1LRRdhyoi8lfU0eSvqaloouw5UReS +vqaPJX1NS0UXYcqIvJX1NHkr6mpaKLsOVCKu0YFLRRSKCiiigAooooAKKKKA +CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//9k= + +--001a1140ffb6f4fc63053a2257e2-- + +--xYzZY +Content-Disposition: form-data; name="to" + +inbound@inbound.inbound.com +--xYzZY +Content-Disposition: form-data; name="from" + +Example User <test@example.com> +--xYzZY +Content-Disposition: form-data; name="sender_ip" + +0.0.0.0 +--xYzZY +Content-Disposition: form-data; name="envelope" + +{"to":["inbound@inbound.inbound.com"],"from":"test@example.com"} +--xYzZY +Content-Disposition: form-data; name="subject" + +Raw Payload +--xYzZY +Content-Disposition: form-data; name="charsets" + +{"to":"UTF-8","subject":"UTF-8","from":"UTF-8"} +--xYzZY +Content-Disposition: form-data; name="SPF" + +pass +--xYzZY--
\ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/send.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/send.py new file mode 100644 index 00000000..8dbfa68d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/inbound/send.py @@ -0,0 +1,61 @@ +"""A module for sending test SendGrid Inbound Parse messages. +Usage: ./send.py [path to file containing test data]""" +import argparse +import sys +from io import open +try: + from config import Config +except ImportError: + # Python 3+, Travis + from sendgrid.helpers.inbound.config import Config +from python_http_client import Client + + +class Send(object): + + def __init__(self, url): + """Create a Send object with target `url`.""" + self._url = url + + def test_payload(self, payload_filepath): + """Send a test payload. + + Load a payload from payload_filepath, apply headers, and POST self.url. + Return the response object. + """ + headers = { + "User-Agent": "SendGrid-Test", + "Content-Type": "multipart/form-data; boundary=xYzZY" + } + client = Client(host=self.url, request_headers=headers) + f = open(payload_filepath, 'r', encoding='utf-8') + data = f.read() + return client.post(request_body=data) + + @property + def url(self): + """URL to send to.""" + return self._url + + +def main(): + config = Config() + parser = argparse.ArgumentParser( + description='Test data and optional host.') + parser.add_argument('data', + type=str, + help='path to the sample data') + parser.add_argument('-host', + type=str, + help='name of host to send the sample data to', + default=config.host, required=False) + args = parser.parse_args() + send = Send(args.host) + response = send.test_payload(sys.argv[1]) + print(response.status_code) + print(response.headers) + print(response.body) + + +if __name__ == '__main__': + main() |