+ "pmsg1 = email.message_from_bytes(msg1)\n",
+ "pmsg1.get_content_type()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "None\n",
+ "None\n",
+ "yahoo.com!njae.me.uk!1448150400!1448236799.zip\n"
+ ]
+ }
+ ],
+ "source": [
+ "for part in pmsg1.walk():\n",
+ " print(part.get_filename())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "This is an aggregate report from Yahoo! Inc. text/plain\n",
+ "UEsDBBQAAAAIAKdGd0dVgJtgpQEAACMEAAAuABwAeWFob28uY29tIW5qYWUu\r\n",
+ "bWUudWshMTQ0ODE1MDQwMCExNDQ4MjM2Nzk5LnhtbFVUCQADekRTVnpEU1Z1\r\n",
+ "eAsAAQQAAAAABAAAAACVU8tyozAQPGe/guQDJGBtJ67SyrnuJ+yJksVga40e\r\n",
+ "JYns5u8zGFlgO1WpnBiaVk/3aGC7/7ov3sAHZc2vp4qUTzv+8IN1AO1eyBPW\r\n",
+ "RcE8OOtjoyGKVkRxBhG2/tAYoYH/EUdrH4vfRhJGM5pYoIXqubMhahEi+NdW\r\n",
+ "Cy/J+3iGSKsZnRiJnnqpller1Uu92jxXNanX23VdMzp/TGy0A40X5nBph9ge\r\n",
+ "DsqcT1frclWWjE5IJoBJ4j83z9ttgQZMFqQ3irnnVXjmbK/ke+OGfa/CEWY/\r\n",
+ "FrMYbv4KIBrIcELBCUoE0Z6U5p7RqbigwXVncHwmzHFjDTDqMiAjr8Y4YzF5\r\n",
+ "+9QGjlBany15+2+OHuzgJTTK8c2a1CUpSYVjndFMlHYw2I7Rqch46ghvoh9w\r\n",
+ "Um3+MoZXAa9ZRVyl5H2JLIljdCdCQMY8hckgDqDDdUBTeRSLpLd98XpyPKZa\r\n",
+ "MFF1Crd5PnkE0YJvOm/11bUs8YvWvQATQzw2HsLQx4Xoreuvrj1t9qiScqeX\r\n",
+ "OeCVJFuG/6Z+sF2cJnjXY7Fd9C7YyE97w+ji//8AUEsBAh4DFAAAAAgAp0Z3\r\n",
+ "R1WAm2ClAQAAIwQAAC4AGAAAAAAAAQAAAKSBAAAAAHlhaG9vLmNvbSFuamFl\r\n",
+ "Lm1lLnVrITE0NDgxNTA0MDAhMTQ0ODIzNjc5OS54bWxVVAUAA3pEU1Z1eAsA\r\n",
+ "AQQAAAAABAAAAABQSwUGAAAAAAEAAQB0AAAADQIAAAAA\r\n",
+ " application/x-zip-compressed\n"
+ ]
+ }
+ ],
+ "source": [
+ "for p in pmsg1.get_payload():\n",
+ " print(p.get_payload(), p.get_content_type())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 92,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "application/x-zip-compressed <zipfile.ZipFile object at 0x7f6538172208>\n"
+ ]
+ }
+ ],
+ "source": [
+ "for p in pmsg1.get_payload():\n",
+ " if 'zip' in p.get_content_type():\n",
+ " print(p.get_content_type(), zipfile.ZipFile(io.BytesIO(p.get_payload(decode=True))))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 93,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "application/x-zip-compressed\n",
+ " report_metadata : \n",
+ " org_name : Yahoo! Inc.\n",
+ " email : postmaster@dmarc.yahoo.com\n",
+ " report_id : 1448246712.259522\n",
+ " date_range : \n",
+ " begin : 1448150400\n",
+ " end : 1448236799\n",
+ " policy_published : \n",
+ " domain : njae.me.uk\n",
+ " adkim : r\n",
+ " aspf : r\n",
+ " p : none\n",
+ " pct : 100\n",
+ " record : \n",
+ " row : \n",
+ " source_ip : 65.20.0.12\n",
+ " count : 1\n",
+ " policy_evaluated : \n",
+ " disposition : none\n",
+ " dkim : pass\n",
+ " spf : fail\n",
+ " identifiers : \n",
+ " header_from : njae.me.uk\n",
+ " auth_results : \n",
+ " dkim : \n",
+ " domain : njae.me.uk\n",
+ " result : pass\n",
+ " spf : \n",
+ " domain : njae.me.uk\n",
+ " result : softfail\n"
+ ]
+ }
+ ],
+ "source": [
+ "for p in pmsg1.get_payload():\n",
+ " if 'zip' in p.get_content_type():\n",
+ " print(p.get_content_type())\n",
+ " with zipfile.ZipFile(io.BytesIO(p.get_payload(decode=True))) as zf:\n",
+ " fn = zf.infolist()[0].filename\n",
+ " contents = zf.read(fn).decode('utf-8')\n",
+ " root = xml.etree.ElementTree.fromstring(contents)\n",
+ " walk(root)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 105,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def xml_of_part(part):\n",
+ " with zipfile.ZipFile(io.BytesIO(part.get_payload(decode=True))) as zf:\n",
+ " fn = zf.infolist()[0].filename\n",
+ " contents = zf.read(fn).decode('utf-8')\n",
+ " return xml.etree.ElementTree.fromstring(contents)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 98,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def xml_of(message):\n",
+ " reports = []\n",
+ " if message.is_multipart():\n",
+ " for p in pmsg1.get_payload():\n",
+ " if 'zip' in p.get_content_type():\n",
+ " reports += [xml_of_part(p)]\n",
+ " else:\n",
+ " reports = [xml_of_part(message)]\n",
+ " return reports"