Browse Source

Outlook-Adressbücher sync mit Info-Mail

robert 5 months ago
parent
commit
4af5d98220
5 changed files with 1509 additions and 20 deletions
  1. 1121 0
      contacts/data/shared_hash.json
  2. 240 20
      contacts/o365_copy.py
  3. 111 0
      contacts/smtp_mail.py
  4. 35 0
      contacts/templates/info.html.jinja
  5. 2 0
      requirements.txt

+ 1121 - 0
contacts/data/shared_hash.json

@@ -0,0 +1,1121 @@
+{
+  "": -6658233286219379024,
+  "Achim G\u00f6hrisch": 5703615734321046033,
+  "Achim Rheindorf": 8406951836974146748,
+  "Achim Wilcke": 3740435363380704519,
+  "Agostino Rigi-Luperti": -6703684041948498698,
+  "Alexander Bieling": 8524216728842339299,
+  "Alexander Hamacher": -7838708143738722000,
+  "Alexander Jernejcic": -4355339169945152904,
+  "Alexander Kiefer": 4209236481961996197,
+  "Alexander K\u00e4stner": 1543383690406676290,
+  "Alexandra Jablonski": -7367256321878974812,
+  "Alexandra Neumayer": -1806294923624838938,
+  "Alexandra Rau-Oelkers": -4278931427907638658,
+  "Alfred Fuchs": 8387322335251954948,
+  "Alim Bayhan": -1948304200705773367,
+  "Alin Manta": 4939551815037392234,
+  "Alina Rimbach": -9186577049112669413,
+  "Alois Rauchegger": -5184890083066469322,
+  "Amin Saib": -2475767430577526702,
+  "Andre Lackermann": -8657356188394047285,
+  "Andre Obermeit": -3608244917861974824,
+  "Andre Ripke": 5930234134004183338,
+  "Andre Schmidt/ PC-Visit": 2542118173847646366,
+  "Andre Toth": -5551134122707354180,
+  "Andrea Bresa": 5505502139741797912,
+  "Andrea D\u00f6rr": -1791768328104614722,
+  "Andrea Funk": -8485870036718892789,
+  "Andreas Andrees-Mersch": -793651188899164966,
+  "Andreas Daube": 8575109288902707411,
+  "Andreas Gaida": 668250434568718307,
+  "Andreas Grabe": -1287124444249966516,
+  "Andreas Greger": -2714293299345895966,
+  "Andreas Gr\u00f6ling": 5205993804178248961,
+  "Andreas Jansen": -4449732637572085624,
+  "Andreas Kr\u00fcger": -5868321818775384928,
+  "Andreas K\u00fchn": -6294800159145039724,
+  "Andreas Matthis": 8323633437913442526,
+  "Andreas Menzel": -399299074229120105,
+  "Andreas Millik": 778765286143493480,
+  "Andreas Neumann": 461752993268408517,
+  "Andreas Podlawski": -3853726714355558488,
+  "Andreas Vierzefski": -986576277582209431,
+  "Andreas Wien": 6050265778407289897,
+  "Andreas Willemssen": 9091670364569353182,
+  "Andr\u00e9 Boldt": -1501889045938355052,
+  "Anett Wien": -7171683267436508386,
+  "Anette Schubert": -1899250010831700163,
+  "Angelika Hanke": 8701611964488328312,
+  "Anina Buchmann": 4799567453751465864,
+  "Anja Entenmann": -8993292317150047934,
+  "Anja Goerigk": -8559940510869553533,
+  "Anja Klintworth": 5516990262028102570,
+  "Anke Beyer": -545334219463506474,
+  "Anke Hym\u00f6ller": -5466071627840879366,
+  "Anke Jonack": 8043194512496455144,
+  "Anna Weis": -4045833852843070989,
+  "Anna Wei\u00df": -2375729800301768961,
+  "Anna-Lisa Weller": -3641072433666556271,
+  "Annemarie Irrschick": -5647101646072440203,
+  "Annett Wauer": -8084122633364328884,
+  "Annkathrin Keil": 1070283616170660385,
+  "Anthony Thomes": 2838733687141301546,
+  "Antonio Matarrelli": 6841187662920110687,
+  "Antonio Ruggeri": -4769803656892693334,
+  "Arne Looden": -2343091460400278714,
+  "Arnold Ladinger": 4718121543191657023,
+  "Arthur Podolski": 2565670991966188890,
+  "Asia Restaurant ASIA Imbiss": 2792436238197434442,
+  "Assmann;  Georg": -5307226149740582271,
+  "Astrid Hermann": 2567557353231191171,
+  "Axel Mosig": 8215790655209478248,
+  "BPI Stellantis Hotline": 7978548605141309131,
+  "Baier Herr Baier": 6108178745581189351,
+  "Baldrich, Leon": -6349455826477968881,
+  "Barbara Simon": 7120737420702012639,
+  "Barbara Toussaint": 326618555047384672,
+  "Barten Frau Barten": 5329477565414096071,
+  "Bastian Pukrop": 1599252207528182601,
+  "Bastian Vogel": 6913064337127593177,
+  "Belia Frau Belia": 1397302720638933874,
+  "Benjamin Bajraktarovic": 2753431286308304980,
+  "Benn Christiansen": 1205404217125544567,
+  "Bernd Bitzer": 867365580843320729,
+  "Bernd Conrad": -2073523683771911349,
+  "Bernd Kadner": 8318174808720543208,
+  "Bernd Markwardt": -228310104456296523,
+  "Bernd Pfeifer": 8755696248363966575,
+  "Bernd Rodemich": 8929068440986140072,
+  "Bernd Schm\u00e4dicke": 1148276027473037372,
+  "Bernd Schreiber": 4660471607116115622,
+  "Bettina Hesch": 5328667938806445911,
+  "Bettina Langenhan": 7375908693950297884,
+  "Bianca Lung-Winkler": -4523000697063079799,
+  "Bijan Drela": -3411471347477477897,
+  "Bilal Tebque": -4503709864843658657,
+  "Bille": -3413338655349177237,
+  "Birgit Bucher": 8852366059842498380,
+  "Birgit Dallmann": -8407080248278478852,
+  "Bittner Frank": -4641792104388118464,
+  "Bj\u00f6rn Drunagel": -5322077587569830728,
+  "Bj\u00f6rn Harmening": 3854180369051270713,
+  "Bogdan Czajkowski (IT)": 2266132017581816510,
+  "Brigitte Gutsche": -8327725174273765041,
+  "Britta Biendarra": 7416267635479019591,
+  "Britta Breuer": -4322691179035152396,
+  "Burkhardt Schmitt": 1281291195825790140,
+  "Busse Busse": -742470773417689604,
+  "B\u00e4rbel Seeger": -3996840778228794889,
+  "B\u00fcrgerhaus Hausen": 4912743045294800065,
+  "CDK support CDK support Autosys": -2461097078569611115,
+  "CDS (externe IT) Denk": -8988421156886328345,
+  "CDS (externe IT) Zinovik": 5775838139778716918,
+  "Caglar Yakut": 6065554744020892657,
+  "Carina Hohlbein": -656134938338409026,
+  "Carmen L\u00f6pelt": -1626645476698512891,
+  "Carolin Doberenz": 7449180863954863499,
+  "Caroline Arnh\u00f6lter": 71106982557511077,
+  "Carsten Schumann": 3254506914637088947,
+  "Carsten Sch\u00f6negge": 8052196699957861745,
+  "Carsten Wiegers": -5886863212008195869,
+  "Celine Roscher": 6461702974238363347,
+  "Charlotte Ru\u00dfig": -6321749335214841573,
+  "Chris Wendrock": -2504402946007890609,
+  "Christian Aichinger": -1068117339911108321,
+  "Christian Bartsch": -8125572731134158265,
+  "Christian Dornieden": -9173633962221784175,
+  "Christian D\u00f6bler": 4293375441533664942,
+  "Christian Fuchs": 5297172057327069600,
+  "Christian Hoffmeister": 105278475938652641,
+  "Christian Janssen": -52061308055496454,
+  "Christian Lehner": -6489003217825426758,
+  "Christian Meures": -4353447677564060626,
+  "Christian M\u00f6llerherm": -6467422129825209195,
+  "Christian Schiffmann": 2822606827465193665,
+  "Christian Schulze": 8924160391773645976,
+  "Christian Simon": -6309571250794634736,
+  "Christian Wedekind": 6262185527813784747,
+  "Christian Weiler": -762207252552965810,
+  "Christian Wopienka": -1713932857265249825,
+  "Christiane Scholze": 3968893460296511639,
+  "Christiane Wiesner": 2222674528345021217,
+  "Christina Haese": 8833325221058440641,
+  "Christina Hafner": 5687344809245234082,
+  "Christina Kleis": 7607132658370054148,
+  "Christina Pichel-K\u00fcnstler": -3083469843228942746,
+  "Christina Winkler": 7906386379331888075,
+  "Christine Wiesner": 7422405609702440069,
+  "Christof Steinhauser": 2849213745581157055,
+  "Christofer Zumb\u00fclt": 5324790157155587790,
+  "Christopher Koller": 8773368008525892327,
+  "Chritian Erbe": 5513096870030208892,
+  "Chritiane Fletcher": -4353779327428296090,
+  "Clarendal Clarendal": -230502226068037578,
+  "Claudia Behrens": -3921251406090843458,
+  "Claudia Schiffel": 574393771113171293,
+  "Claudia Schmelter-Beul": 4882210300364519814,
+  "Claudia Sirch - Miller": 8983449503581126876,
+  "Claudia Sommer": 1030406043236007712,
+  "Claudia Zopf": 4542842040451442884,
+  "Claus Bauernfeind": -3608152866737783267,
+  "Claus Wiese": -263005564735940764,
+  "Constanze Schwab-Winter": 1719038994183510384,
+  "Cord Schneider- PC Visit": -8730583694953663998,
+  "Cornelia Grabe": -1866354632769659892,
+  "Cornelia Gruber": 1712792030861770047,
+  "Dan Jitiano": -8219180385269208635,
+  "Dana Tamm": 3338510157410509619,
+  "Daniel Dornig": 3346908173020449992,
+  "Daniel Fuhrmann": 7187092013228752713,
+  "Daniel Hewener": -3736328305111718423,
+  "Daniel L\u00f6sching": 2006987802394884659,
+  "Daniel Mann": 8024316903913864919,
+  "Daniel M\u00fcller": -6476217970721643442,
+  "Daniel Widura": -1452830380839152190,
+  "Daniela Kienle": 1912228503232169379,
+  "Daniela Stein": 8923072096712910110,
+  "Danny Koch": -8963118464856218846,
+  "David Martinez": -3827123067247845373,
+  "Demmelhuber Frau Demmelhuber": 744560138799125748,
+  "Denis Authier": -5343311768266172012,
+  "Dennis Schulz": -8660981884491938605,
+  "Dennis Ziegenhagen": 3109202414676150332,
+  "Detlef Zaja": -8349171241690777279,
+  "Deverson": 7654318308258244421,
+  "Dieter Goldenpfennig": -4660066323153705377,
+  "Dieter Rasel": -8153149868391768217,
+  "Dieter Winkels": 6019545653864850820,
+  "Dietmar Huhs": -4128519992552159977,
+  "Dietmar Seils": 1150142344506352551,
+  "Dietmar Seyerle": -2337278907988847595,
+  "Dirk Fangmeier": 8298747305524836758,
+  "Dirk Gottstein": -2498840798423367671,
+  "Dirk Hugenpoth": -6243710286048841118,
+  "Dirk Wilms": -3541883266770258794,
+  "Discount Office": -2911608911553344964,
+  "Dominik Br\u00fcndel": -2516268944961326146,
+  "Dorota Lukoschek": -2473169883469211944,
+  "Eberhard Fl\u00fcgel": -8635899564479172845,
+  "Elisabeth Henke": 1573111729154166214,
+  "Elisabeth L\u00f6w-Wagner": -664631764772956342,
+  "Elke Graf": 54215602557002525,
+  "Elke Steins": -4356985288045920384,
+  "Enrico Casiraghi": -5569830167827622981,
+  "Enrico Opitz": 1459539952043841987,
+  "Eric Bredy": -1260850138616826820,
+  "Erich Korb": 426342616911827942,
+  "Erik Epple": -4753463577111868432,
+  "Erik Frey": 3713947241496250742,
+  "Erik Zeller": -4143192362865300471,
+  "Eser Herr Eser": 6699308733984308035,
+  "Eva Lauble": -8264524087777708389,
+  "Eva Psotka": 3875091276166234093,
+  "Evelyn Gehrke": 503221829600950324,
+  "Evelyn Kranefeld": -5855503157595696966,
+  "Evers Evers": -1255235287710553281,
+  "Fabian Beck": 7151341272945404100,
+  "Fabian Klose": 8121879040340175287,
+  "Fabian Tiefert": -6921446755089645247,
+  "Fabricius, Walter": -3832129856384970321,
+  "Fangmeier, Dirk": 4605635535610972951,
+  "Fazil Dolan": -8370768710933522540,
+  "Felix Emrich": -1812535892932415020,
+  "Felix Komarek": -1322157811303603333,
+  "Felix Wistokat": 5468562315732382881,
+  "Fellgiebel Herr Fellgiebel": 6360478936747809729,
+  "Ferdinand Wiengarn": -705937105736529037,
+  "Fiat Fiat Hotline (AT) (AT)": -2833371073127520177,
+  "Fiat Fiat Hotline (DE) (DE)": 798490409710495988,
+  "Fisch Fricke": 1061972434529948931,
+  "Fleitmann Frau Fleitmann": -2897325167858306714,
+  "Florian Bitz": -2357812244190304514,
+  "Florian Greiner": 1815505943025629738,
+  "Florian Hutter": -8143196566963931201,
+  "Florian Mehsing": -4553782015577918510,
+  "Florian Wenig": -1115529005096758456,
+  "Ford-Hotline Ford-Hotline": -6446063012538104044,
+  "Francisca Venuto": 2146222675367446488,
+  "Francois Dussuet": -4934432870277968201,
+  "Frank Heister": 1525510524986212736,
+  "Frank K\u00fcthe": -1196976753586757639,
+  "Frank Malewicz": -955861139977813531,
+  "Frank Neustadt": -2022218933036300475,
+  "Frank Rentsch": -4507991880928369624,
+  "Frank Ritzrau": -1589291325952355020,
+  "Frank Schaubs": -8378600981486602575,
+  "Frank Wolff": -7427602343125248849,
+  "Franz Espeter": 2296457899619188064,
+  "Franz Fleischanderl": 8155076324966566259,
+  "Franz Kropfeld": 1066647091941970628,
+  "Frau Aldejohann-Baldus": 7723913789351140148,
+  "Frau Alexandra Jablonski": -5058538020012926999,
+  "Frau Brose": 137497311770677252,
+  "Frau Bujor": -8560065204761380115,
+  "Frau B\u00f6cker": 424431351665390485,
+  "Frau Chris Lauterbach": -3890870912708518847,
+  "Frau Cierocki": 9101899357775109171,
+  "Frau Elle": -198440423461589587,
+  "Frau Faber": 1426117630999840612,
+  "Frau Fageth": 9045352367047446752,
+  "Frau Fl\u00fcgel": 1108831366758490981,
+  "Frau Franke": -6648170177254384636,
+  "Frau Gaudien": -2909648189618241726,
+  "Frau Grau": 7640103261750946322,
+  "Frau Gundermann": -5084507423348451474,
+  "Frau Haltaufderheide": -8760262415895881354,
+  "Frau Hantke": 631351088252268637,
+  "Frau Hartl": 2351763076003996719,
+  "Frau Herbstritt": -6097504458371399496,
+  "Frau Hinz": 3127149822611759406,
+  "Frau H\u00e4rterich": 7090376294608946412,
+  "Frau Jansen": 5470182143925494191,
+  "Frau Jetter": 697916322231185496,
+  "Frau John-Leitner": -4646256005131426971,
+  "Frau Kamp (Fibu)": 5724649512985004045,
+  "Frau Kathan": -4083334032671077903,
+  "Frau Klassenb\u00f6ck": -7284894630946943013,
+  "Frau Koj": 5488060141089693467,
+  "Frau Kottenbach": 1839905560579357162,
+  "Frau Kwiatowski": -6406928662033603086,
+  "Frau K\u00f6hler": 2282577372888144593,
+  "Frau Lange": 452042223269267308,
+  "Frau Lippitsch": 3486843404209634417,
+  "Frau Loitsch": -2501160903477776205,
+  "Frau Mitschke": 4159830193994623336,
+  "Frau M\u00fcller": -591619949466058354,
+  "Frau Nehm": -3901570645917210761,
+  "Frau Paulsen": 2679612780032380860,
+  "Frau Pirzadeh": 7449207667406023066,
+  "Frau Rachlok": 2300251130214645589,
+  "Frau Raml": -386659879951798155,
+  "Frau Raubold": 4121130411520420175,
+  "Frau Reinhard": -9057041565319260117,
+  "Frau Reinhardt": 8212312911982761238,
+  "Frau Reisacher": 1650522089993076657,
+  "Frau Reithofer": 7081239253363353757,
+  "Frau Reuter": 1327641488494925791,
+  "Frau Saathoff": -3521847343522618309,
+  "Frau Schellenbacher": 2193662466575515697,
+  "Frau Schottenheim": 22655980225828234,
+  "Frau Schramm": 2368419775393830991,
+  "Frau Schubert": -2460800379472128036,
+  "Frau Seifert": -3818663162196962532,
+  "Frau Stecher / PC-Visit": -3104683427238908509,
+  "Frau Strobel": 8298827435065342221,
+  "Frau Strunk": 7456509706434185995,
+  "Frau Tosun": -4446291274653389135,
+  "Frau Treger": -5045396772818287870,
+  "Frau Ulrich": 6500687156656257723,
+  "Frau Urgatz": -8431607224602691845,
+  "Frau Weber": 4790704649892688098,
+  "Frau Weinmann": 2503422203355496844,
+  "Frau Winterhoff": 2426683600986877172,
+  "Frau Wolter": 1358839745777413201,
+  "Frau Zolles": -6415385756128205813,
+  "Fred Meyer": 2196481097504289764,
+  "Fred Neuh\u00e4usel": 787616925851085833,
+  "Freshdesk": 1639012933912576405,
+  "Freya Burghard": -8456671854283883544,
+  "Friedrich Hartmann": 1261826537329959250,
+  "Frithjof Schl\u00f6gel": 5502035097686742713,
+  "Fr\u00fchauf Herr Fr\u00fchauf": 7781783577688075552,
+  "Futzi Neu-Burger": -5934692468636231942,
+  "GC Vodafone": -1648672926810610134,
+  "Gabriel Wolgast": 5964236571352764973,
+  "Gabriele Pichel": -3553866006162614210,
+  "Gabriele Sternbeck": -3584650184180378766,
+  "Geert Schmidt": -986470161223328421,
+  "Geertje Westervelt": 5461062903081507916,
+  "Georg Arndt": -4265279633194137429,
+  "Gerd T\u00fcmmers": -7758483896402286279,
+  "Gerhard Bedner": 7540168970691055161,
+  "Gerhard Eberl": -7815859347175411575,
+  "Gerhard Regelmann": -4818061371626202740,
+  "Gerhard S\u00f6bbing": 250763436703201876,
+  "Gerhard Thress": -7840435200614104133,
+  "Gerhard Trapp": 2487160081911714584,
+  "Gisela Hanser": -7933670539281257173,
+  "Global Cube Zentrale": -6804985037687719903,
+  "Gregor Becker": -384384639574752580,
+  "Guido Weyland": -5521557722986531866,
+  "Gutowski Herr Gutowski": 9210026912254165812,
+  "Gyuner Veysal": 4666074625405853951,
+  "G\u00fcnther Hennig": 8176357151615007310,
+  "G\u00fcnther Zadrasil": -5315377208154524390,
+  "Hans Matschiner": 4195265231927374448,
+  "Hans Tenhaft": -2270185340117920069,
+  "Hans Zimmermann": 7407044247744663857,
+  "Hans-Heinz Bieling": 8548488419078548491,
+  "Hans-Joachim Flohr": 9193524525803814222,
+  "Hans-Joachim Ruthe": 4424011426977065997,
+  "Hans-J\u00fcrgen Kley": -5456179513046912703,
+  "Hans-Peter Sch\u00e4fer": -1048961212996558243,
+  "Hans-Peter Werner": 5035832843938084785,
+  "Harald Feldbacher": -2151333382666378984,
+  "Harald Krammer": 1100032217188513287,
+  "Harald Sustrate": 8769723103156541812,
+  "Harry Thiele jun.": 8177652633643254761,
+  "Hartmut Joswig": -5398974913780205967,
+  "Heidi Hersener": 1460163295621231609,
+  "Heike Boras": 1349855896853773425,
+  "Heike Crysandt": -4706594816610335787,
+  "Heike Engelhardt": 5982276409353527939,
+  "Heiko Winter": 592457674996464863,
+  "Heiko Zelch": -5701753627242737796,
+  "Heimers Herr Heimers": -5877432061177910790,
+  "Heinz Prei\u00df": -2483280182318046222,
+  "Helena Stuplich": 3009637729831116462,
+  "Helga Moll": -6538826749100266242,
+  "Helmut K\u00fcsters": 3040867290482620780,
+  "Helmut Pekert": 4654002494022751246,
+  "Hendrich Michael": 5560245547235866501,
+  "Hering, Dean Marvin": 4406832618770316857,
+  "Hermann Vierlbeck": -6997400161640818296,
+  "Herr ACP": 6783940836373023888,
+  "Herr Altmann": -83498357405466529,
+  "Herr Amelung": 8825507948164559599,
+  "Herr Assmann": -8730001921702713154,
+  "Herr Baran": -5739240550603257045,
+  "Herr Barsch": -1699026073746440725,
+  "Herr Baussmann": 6969922850119043193,
+  "Herr Benjamin Fuegle": 5910339011411915055,
+  "Herr Bistrizky": 6056146383194664026,
+  "Herr Bittner": -6226192608549779464,
+  "Herr Buchholz": 5786772845874761922,
+  "Herr Budi": -6521211515906114786,
+  "Herr Cusmano": -2182007278744248628,
+  "Herr Dahl": -405043791945293868,
+  "Herr Dausner": 6888521253799774274,
+  "Herr Dechancsreiter": 6405949662815166839,
+  "Herr Doser": -3961205810054540086,
+  "Herr Droege": -2127198151541547769,
+  "Herr Edlinger": 3006583280707832301,
+  "Herr Elle": -8319084734209837444,
+  "Herr Enderlein": 9038479874302059921,
+  "Herr Ertle": 1463082153260823757,
+  "Herr Etzl": -2785904131283801873,
+  "Herr Feuerherm": 7426466092232586949,
+  "Herr Fiedler": -1041929509744118595,
+  "Herr Geisbauer": 6500041705936026188,
+  "Herr Geldmacher": 431795590638736055,
+  "Herr Gerke": 4851932380891897695,
+  "Herr Giarolo": -3887840976969282510,
+  "Herr Goller": -7077095601039442923,
+  "Herr Grau": 3694477908898930116,
+  "Herr Grauel": 7259657987437472219,
+  "Herr Gr\u00fcnke": -8908695580526512439,
+  "Herr G\u00f6bel": -773186019034175549,
+  "Herr Hage": 9215171424100760222,
+  "Herr Halang": 1891293986975151629,
+  "Herr Hannuschka": -1125939565327326013,
+  "Herr Heidenreich": 5900337201370511747,
+  "Herr Heimann": 7852314975958358893,
+  "Herr Helms": -1747006004246451079,
+  "Herr Herr Frenzel": 6679780661999510660,
+  "Herr Hieke": -4638492688924220500,
+  "Herr Hilzendegen": -265483940461824399,
+  "Herr Hintze": 1817139053520675372,
+  "Herr Hochstrat": -896598298086048545,
+  "Herr Hoffmann": 3605399977149896675,
+  "Herr Holz": -2934856010295763115,
+  "Herr Horn": -8600814620358121512,
+  "Herr Iding": 3543274663151944035,
+  "Herr Ihfe": 7815512597827916171,
+  "Herr Jakubik /Brznak": 7037023278419111289,
+  "Herr Kachel": -1963310364402065566,
+  "Herr Kawalla": 8445381820566682001,
+  "Herr Kazmierzcak": -1353231063716640251,
+  "Herr Keppeler": -6131176187555048744,
+  "Herr Kleinmann": -5080309912177691486,
+  "Herr Knieriem": 2094337218109061953,
+  "Herr Kremer": 514357737502880674,
+  "Herr Kr\u00fcger": 348572620945335986,
+  "Herr Kuric": 5487255393364199273,
+  "Herr K\u00f6nig": 6593387888210972952,
+  "Herr K\u00f6tz": -8056797188456179965,
+  "Herr Lange": 3396718606592223929,
+  "Herr Lippold": -765021625935893258,
+  "Herr Lorig": 1082835214737538259,
+  "Herr Ludewig": 8638031698860401958,
+  "Herr Lumme": 6321780684222808584,
+  "Herr L\u00fcbke": -5293501544123848681,
+  "Herr Mahlburg": 4502513797954694417,
+  "Herr Meyer": -8057810264622265197,
+  "Herr Michelis": 4238816230621938133,
+  "Herr Miehle": -7062226348482731028,
+  "Herr Minut": -2414464889292876536,
+  "Herr Mroz": -6133636293173356015,
+  "Herr M\u00fcller": -429202918562542726,
+  "Herr Nittka": 1537249447222086468,
+  "Herr Novak": 4357813303724647556,
+  "Herr Novara": 1666711359491258314,
+  "Herr Nowitzki": 5248957812879112962,
+  "Herr Ochs": 6611484350164388153,
+  "Herr Ophoven": 440444998141346639,
+  "Herr Otten": -1208765129356812075,
+  "Herr Otto": -2850651999227471845,
+  "Herr Penther": -6337265736215744042,
+  "Herr Peschke": -5688283866258603820,
+  "Herr Peters": -6738759622923828994,
+  "Herr Petzold": -2084200547678386050,
+  "Herr Pfau": 3625387302565744197,
+  "Herr Pilger": -5723454764170150169,
+  "Herr Plesnik": -6284189544810758660,
+  "Herr Preuschoff": -6896907520888655936,
+  "Herr Prevot": 4743932644732913300,
+  "Herr Privot": -1581203379420397580,
+  "Herr Prumbaum": -4736405418521182215,
+  "Herr Quasthoff": -7001248692235384392,
+  "Herr Rader": 3280411083775724836,
+  "Herr Rehmann (IT)": -5280310313765420296,
+  "Herr Rock": 521396180001890202,
+  "Herr Rottenfu\u00dfer": -3778958898253421698,
+  "Herr Sachse": -4631676531226692138,
+  "Herr Saib": -5681539929007067812,
+  "Herr Schaller": -6792678697342792543,
+  "Herr Schiffer": 8301263280327499221,
+  "Herr Schildbach": 8543290386965125929,
+  "Herr Schlo\u00dfhan": 3925002044689510632,
+  "Herr Schmied": 4956857789467683333,
+  "Herr Scholl": -1736366875417746713,
+  "Herr Schraml": 2351224266191857077,
+  "Herr Schremmer": 3025288004236845420,
+  "Herr Schulmeyer": -2019655003656891532,
+  "Herr Schwarz": 7894257268345390487,
+  "Herr Sch\u00e4fer": 6154344110497812341,
+  "Herr Sch\u00e4fer ext. IT Fa. Netplan": -2713377536422817983,
+  "Herr Sch\u00fcch": -1502665965963105446,
+  "Herr Scwalski": 8046359350296233339,
+  "Herr Sellschopp": -5914875888857816084,
+  "Herr Serdar \u00dcnal": -4565992335007130578,
+  "Herr Siegler": 8845147268773656597,
+  "Herr Sleegers": -6000454491763203914,
+  "Herr Sontowski": -5957701560334223320,
+  "Herr Specht": -4991954067176406864,
+  "Herr Spilker": 7317180033387998907,
+  "Herr Starke": 8500402279395580986,
+  "Herr Steffens": 620064156525242252,
+  "Herr Stein": 2289078477850277784,
+  "Herr Steingass": 3305684450845248447,
+  "Herr Streng": 1424297429394345542,
+  "Herr Szellates / PC-Visit": 44686306699766930,
+  "Herr S\u00fclberg": -4279418165310637840,
+  "Herr Tautz": 6728721665139028543,
+  "Herr Te\u00dfmer": 6420047525179824078,
+  "Herr Thomas K\u00f6ser": 4940603961528054700,
+  "Herr Tintemann": -8092404734255393457,
+  "Herr Tretter": 7805028580032154892,
+  "Herr T\u00fcrschmann": 7174842535907548003,
+  "Herr Vassios": -7068484267663679718,
+  "Herr Weber": 8247425334588190128,
+  "Herr Wei\u00dfpfahl": 3174396040103297040,
+  "Herr Werner": 3175354154419768669,
+  "Herr Westerbur": 7402516010494017908,
+  "Herr Wiedemann": -7044729271447872114,
+  "Herr Wiedmann": -7749901952055097615,
+  "Herr Wienskowski": -5658582710103681511,
+  "Herr Wies": -5145585533157524671,
+  "Herr Winne": -3177208097160678451,
+  "Herr Witting": -4489800279611980275,
+  "Herr Woicek": -7624077622791455275,
+  "Herr Zschernitz": -2270406293360607341,
+  "Herrmann Troger": -113813186842400410,
+  "Hofacker Herr Hofacker": 4483777165853730889,
+  "Hoffmann, Martin": -7478595236331480416,
+  "Hofmann Hofmann": 7706093496005514613,
+  "Holger Golenia": 5826720506061799771,
+  "Holger H\u00f6pken": 1489437123179098805,
+  "Holger Kern": 2369884826571179525,
+  "Holger P\u00f6llmann": 363452147983470095,
+  "Holger Schramm": -7329438010720216984,
+  "Honda Hotline Honda Hotline APD": -8080547325338606601,
+  "Hotline Hotline Volvo": 2595354702111253170,
+  "Hotline Thold Hotline Thold IT": -4351615042887031209,
+  "Hubert Mangler": -5548919557173256530,
+  "Hym\u00f6ller, Anke": 468764181684382279,
+  "H\u00fcseyin Seslikaya": -6489323511470050434,
+  "Ilko Hoffmann": -4756181074612566164,
+  "Imke Thomas": -2116186094727617839,
+  "Ines Br\u00fcckner": 5413116960223467320,
+  "Ines Paulesits (IT)": 4886051464675328522,
+  "Ines Sch\u00f6nheid": -5652847717602993536,
+  "Ines Seibt": 2106242626869385667,
+  "Inge Gehrtz": -4568164066453189361,
+  "Ingo Hofmann": 4140277427867073096,
+  "Ingo Kuschminder": 6359563541125273699,
+  "Ingo Roeske": 9062418151959058265,
+  "Ingo Stahmann": -7453042491955779986,
+  "Irina Bauer": -1563540515535742192,
+  "Isabell Richter": -1357990725956593202,
+  "Isabell Winter": -514122780604337051,
+  "Jacqueline Wever": -1283282316727767670,
+  "Jan Albinski": 3029070868627210423,
+  "Jan Bach": -473630280805289024,
+  "Jan Busse": 1848512511338168868,
+  "Jan Elspass": 5941061675580181968,
+  "Jan Fromme": 4624729828939503643,
+  "Jan Hinkelmann": -7209391774168566361,
+  "Jan Scholz": -3991816035281047419,
+  "Jan von der Weppen": 9118697468122494536,
+  "Jana Wentzel": 5858990791729196368,
+  "Janete K\u00fchn": 3242237364327079384,
+  "Jenny Mingers": -4309965990563599220,
+  "Jens Dracker": 958555530164627202,
+  "Jens Heller": -4664191285486578785,
+  "Jens Prei\u00df": -7381343970193239817,
+  "Jens Reimann": 2267829286377890629,
+  "Jens Scharfenberger": -3248025945391673655,
+  "Jens Thielemann": 2200790735542945038,
+  "Jessica Rill Reif": 3861683507250143275,
+  "Jessica St\u00f6ckle": -2759570331677810258,
+  "Joachim Berger": -4663092002106441651,
+  "Joachim Eschert": 326385073137131073,
+  "Joachim Kr\u00e4mer": -1048227710501221700,
+  "Joachim Wiest": 6816859387518233505,
+  "Joan Hendrik R\u00fcschkamp": 3568885367511252964,
+  "Jochen Bachmann": -5983344832462219430,
+  "Johann Santner": 6824879929991763192,
+  "Johannes Weber": -5143454380030139668,
+  "Josef Stra\u00dfl": 7513648933075645542,
+  "Joy Feiner": 8691694163415483949,
+  "Julia Petermann": 1902599867957336984,
+  "Julia Schumacher": -7212572332963628894,
+  "Julian Bobinger": -3072232893891503498,
+  "Julius Emrich": -449865401166879038,
+  "Jung-Hyun Lee": 5955963983897367189,
+  "Junghans Herr Junghans": -5533962617777979152,
+  "Jutta Haas": 5464844285489125960,
+  "J\u00f6rg Heidenreich": -4674319416770042082,
+  "J\u00f6rg Kaufmann": -2849902141210565976,
+  "J\u00f6rg Lackermann": -2186098071471527656,
+  "J\u00f6rg Schreiber": 8934937735223606708,
+  "J\u00f6rn Heuer": -6342324005208892630,
+  "J\u00f6rn Waldeck": -7241574672161337804,
+  "J\u00fcrgen Geuss": -7871191545551959668,
+  "J\u00fcrgen Gottwald": -369996835873951640,
+  "J\u00fcrgen Koppenh\u00f6fer": -1340705805613792294,
+  "J\u00fcrgen Matthes": 6041538036572904262,
+  "J\u00fcrgen Strenger": -1417368393614784122,
+  "KIA Hotline (Fr. Deverson)": -3283268210576814103,
+  "Kai Jonas": 3145284837391333587,
+  "Karin Baumann": -7875422914911282438,
+  "Karin Zahner": 4685492977368127405,
+  "Karina Krause": -478593510829612453,
+  "Karolina Eres": -1326954962248797446,
+  "Katja Zanger": 3461757435555647633,
+  "Katrin M\u00fcller": -3335800696569915284,
+  "Kay Arnh\u00f6lter": -6586077744731176704,
+  "Kay Oelkers": 1739490458212791563,
+  "Kemal Veran": -5505072835351348341,
+  "Keppeler Herr Keppeler": 4209801619969368855,
+  "Kerstin Karcher": 1468758616799768685,
+  "Kerstin Kr\u00fcger": 7380558487015042503,
+  "Kerstin Thiermann": 4828247073822080967,
+  "Kevin Baumann": 6078274921317486536,
+  "Kevin Walde": 2453942138863167602,
+  "Kim L\u00fchmann": -8135701631484682199,
+  "Kim Speckmann": 2352499845643918811,
+  "Kirsten Dehen": -2966696565555447578,
+  "Klaus Ecke": 327377599420514959,
+  "Klaus Ecke (Wahl Group)": 3956966786048025259,
+  "Klaus Grimm": -4870091977694941803,
+  "Klaus Gutberlet": -2008059012907029364,
+  "Klaus Keller": 7266697085121023703,
+  "Klaus Mulfinger": 8204451708745737194,
+  "Klaus M\u00fcller": -4098400687924832407,
+  "Klaus Pawlowski": -5682607644154916317,
+  "Klaus Plenge": 3586049875414073914,
+  "Klaus Sch\u00fcrer": -6140933258602403911,
+  "Klingler Herr Klingler": 27039247931832860,
+  "Knut Sch\u00e4fers": -3316686771643320221,
+  "Kokahn Herr Kokahn": 6337237840973106304,
+  "Konrad Rabel": 6631922398610440410,
+  "Konstantin Lebed": -2936549636051212683,
+  "Konstantinos Katziotis": 4015563435336483706,
+  "Konstanze Saar": 2093969128236371985,
+  "Kramp;  Regina": 561002118443880604,
+  "La Corona": -7411273318896366388,
+  "Landrover - BMI Hotline (ASE)": 2605644186914521958,
+  "Langenberger Langenberger": -371809474187699449,
+  "Lars Haseloff": -3671092755368405192,
+  "Lars Vollstedt": -249746282174352199,
+  "Lask Frau Lask": -5624447550095434477,
+  "Lehnen Frau Lehnen": 1222000760871103585,
+  "Lemongrass Lemongrass": 79269377787126816,
+  "Linda Liehr": -5674136585353113973,
+  "Lisa Gierschner": -1670413800828865371,
+  "Ludwig Feuser": -2840839385296230946,
+  "Luigi.Gagliardi": -6313013417145419299,
+  "Luis Galvez": 6026793492066814441,
+  "Lukas Blum": -8944712846559155928,
+  "Lutz Haeger / PC-Visit": 2093778066949189841,
+  "Lutz K\u00f6hler": -8849300240684221694,
+  "MIchele & Gianluca Due Fratelli": -3962110999969078574,
+  "Magdalena Fait": -201077090936566114,
+  "Maik Altermann": -6319020408507129725,
+  "Maik Barion": -4118077627073942813,
+  "Maik Lackermann": -4688532093198647821,
+  "Maik Mangelsdorf": -8857953329535299108,
+  "Maik Mucke": -4724893601776112223,
+  "Manfred Haida": -3751557116258791539,
+  "Manfred Kammann": 8325506825318124250,
+  "Manfred Traub": 4418160817862161466,
+  "Manfred Wildmoser": 8149070381379910654,
+  "Manuel L\u00f6ckinger": -7953292081553175780,
+  "Manuel Schmallenbach": -4749810205834924039,
+  "Manuel Zimmer": 5867344443769591290,
+  "Manuela Dohle": 311686234129773103,
+  "Manuela Kr\u00fcger": -5885467362374064410,
+  "Manuela Piersig": 281123277531530773,
+  "Marc Fischer": 6507877890670096266,
+  "Marc Helm-Krais": -6055947550116493816,
+  "Marc Kappler": 4232596095966520407,
+  "Marcel Hartmann": 6767848676111934095,
+  "Marcel J. G. Kamps": -5121332268427583860,
+  "Marcel Leutloff": 1897054188972607932,
+  "Marcel Schuler": -7346487284760233884,
+  "Marco Arnold": 658641070048416998,
+  "Marco Geiss": 6403817228110791543,
+  "Marco Gei\u00df": -5801876419266250132,
+  "Marco Kerst": 4705870514024519641,
+  "Marco Ortseifer": -4776071420974161381,
+  "Marco Steinke": -3443900832386502626,
+  "Marcus Sch\u00e4fer": -2461290883186241563,
+  "Margit Bedner": 656801336709211215,
+  "Margit K\u00f6ck": 4352126821742786273,
+  "Maria Dietrich": 8518754589801023918,
+  "Maria Wengert (Tasca)": 1417811831933632843,
+  "Marika Arnold": 2233400786029823574,
+  "Marina Grebenstein": 5792534061449722189,
+  "Marina Vesting": 7499154067425961736,
+  "Mario B\u00f6ttche": -8705714967668471708,
+  "Mario M\u00fcller": 3537494394216434485,
+  "Marion Bautze": 4370534858836736084,
+  "Marion Hinkel": 6419621018033767303,
+  "Marion Reichard-Hamann": -3271351201421382288,
+  "Marius Janowitz": 8748374396271366893,
+  "Marius Kling": 8583961684710220550,
+  "Mark Olfmann": -6094055145645874422,
+  "Mark Peters": -1705875306910422452,
+  "Marko Langer": 3632245774757345457,
+  "Markus Blanke": -5131002870268075527,
+  "Markus Heukrodt": -3383841617235460428,
+  "Markus Hofmann": 5797495939995018585,
+  "Markus Marzodko": 8297731481110542496,
+  "Markus Pfaff": -5129076897825466176,
+  "Markus Schrick": 6364540017011143895,
+  "Markus Trimmel": 7515136113092494704,
+  "Markus Wagner": 1661587334702529130,
+  "Markus Zipfer": 7376838652484512164,
+  "Martin Baader": 8796735622348899650,
+  "Martin Bopp": 3392204377958325909,
+  "Martin B\u00f6se": -2334888814436846155,
+  "Martin Fink": -1592926863709863670,
+  "Martin Haug": -5261184547110224295,
+  "Martin Mohyla": 8731097203846566007,
+  "Martin Paul": 7652692314882370047,
+  "Martin Platz": 8009416987733125384,
+  "Martin Sommerfeld": 38435207332512799,
+  "Martin Sondermann": 8714132439927856222,
+  "Martin Steinraths": -2511443108304088950,
+  "Martin Wahl": 1969032529575550721,
+  "Martin Werner": 6966438301066945318,
+  "Martina Schneider (Beyer & Br\u00fcckner)": 7297575511082113290,
+  "Martyn Leach": -3101188690173161105,
+  "Marvin N\u2019Doye": -6432660050630402162,
+  "Mascha Schniggenfittig": -4571041293058114877,
+  "Maschwitz Andreas": -4865359508455019464,
+  "Matei Christian": 2439089091534993614,
+  "Mateo Videla": 4680297580856136121,
+  "Mathias Justen": -6262354565328381613,
+  "Mathias Menninghaus": -6680922328182200421,
+  "Mathias Schmid": -6406684441858863281,
+  "Mathias S\u00fcchting": 4571234963677286791,
+  "Matios Thomas (ehemals Yigit)": -306708692756693274,
+  "Matthias Berning": 3811008958494754064,
+  "Matthias Jakob": -6075064721711734576,
+  "Matthias Knorr": 5216110106882953047,
+  "Matthias Krieger": 2655454981633479724,
+  "Matthias K\u00f6sters": 4080265284622511478,
+  "Matthias Moll": 7899557315865240858,
+  "Matthias Mundt": 8102788031128438663,
+  "Matthias M\u00fcller": -7104083054048482198,
+  "Matthias Schmidt": -1366481502208332361,
+  "Matthias Spandler": 2441175792742992151,
+  "Matthias Th\u00e4ter": 4700215794877475195,
+  "Matthias Vogel": -1569312805327698969,
+  "Matthias Weise": 4705312955003912109,
+  "Matthias Wei\u00df": -8718003000109739166,
+  "Matthias Winter": -9184513975956202547,
+  "Mattias Ambros": 1040462633423911857,
+  "Max K\u00fcnzli": 9106133295252706007,
+  "Maximilian Schwarz": 1845141742147827098,
+  "Maximilian Wieser": -1576927526306832143,
+  "Metzgerei Picard": -7930730930264159373,
+  "Michael Agsteiner": -3286405095020130367,
+  "Michael Danell": -8347026224787300088,
+  "Michael Derendorf": 6659541907904458566,
+  "Michael Freudenthal": -9174059957294174793,
+  "Michael Gerbecks": 2809029433035211230,
+  "Michael G\u00fcnther": -5371415592105668224,
+  "Michael Haase": -2857221975492732908,
+  "Michael Hanser": 3618816071460272031,
+  "Michael Heise": 4564731093704999024,
+  "Michael Hendrich": 5322950525701210582,
+  "Michael Kaiser": 6818689446133538494,
+  "Michael Kalabund": 1917687076127098508,
+  "Michael Krau\u00df": 6408101324611860247,
+  "Michael Kremerskothen": 1144559890652826906,
+  "Michael K\u00f6nig": -2461454086053151716,
+  "Michael Lenz": 8966113455551649619,
+  "Michael Leymann": 2929901249934413253,
+  "Michael May": -1914616498279755445,
+  "Michael Mende": 4500221097925388047,
+  "Michael Mohaupt": 9163037581593802743,
+  "Michael Schesny": -3070197048121132970,
+  "Michael Schilling": -470083569006050288,
+  "Michael Schr\u00f6der": 4718911941181705894,
+  "Michael Schumacher": -654778030503276342,
+  "Michael Simon": 8979691896937895433,
+  "Michael Trautmann": -9090875199896881526,
+  "Michael Wilke": 2494171769487349942,
+  "Michaela Block": 4195736204649041977,
+  "Michaela Schranner": -8713473784049826217,
+  "Michaela Staffel": 792319418269067015,
+  "Michaela Zimmermann": 8270257826017064178,
+  "Michalak Michalak": 7544217977269200223,
+  "Michele Setti": -2260462310701843911,
+  "Mike Kutrieb": -8906912679493640475,
+  "Mirko Reu\u00df": -6869126164732310620,
+  "Miroslaw Musial": 6188050154463659974,
+  "Mirsada Mujanovic": 8889922146848100928,
+  "Monika Berghold (Fibu)": -675252570831958723,
+  "Monika Gieraths": -1124953766203240046,
+  "Monika Richter": 884235049530289511,
+  "Monika Senske": -7986718420069430324,
+  "Montag Montag": 9136809667856521174,
+  "Muhamed Alic": 5217498362852112283,
+  "Murat Alatas": 1989828085007514796,
+  "M\u00fcller M\u00fcller": 6882255236251419284,
+  "Nadin Raumsch\u00fcssel (Gebhardt)": -5000413721439183208,
+  "Nauheim Stefan": -3513153983170916940,
+  "Neuse, Olf": -2790772743221560998,
+  "Nicole Fr\u00f6hlich": -7102934368019953023,
+  "Nicole Hofmann": -3354102979530005077,
+  "Nijas Safarov": 588577064409337023,
+  "Niki Wesely": 8208569867246526633,
+  "Niklas Leist": -1223146237038413637,
+  "Nils Nelges": -8425379261459674585,
+  "Nina M. Oertel": 6037499178567787309,
+  "Norbert Bruder": -7272957337852356561,
+  "Norbert S\u00f6lker": 3017616984266152397,
+  "Oehmcke Frau Oehmcke": 4297387681456861567,
+  "Olaf Kortegast": 8396611237331604253,
+  "Oliver Marette": 5551879840484144339,
+  "Oliver Mohr": 6693868886722402188,
+  "Oliver Philipp": 6169349607889912078,
+  "Oliver Priese": -2508813300956927448,
+  "Oliver Schenk": -2311024442059954703,
+  "Oliver Wirkner": -2965266527331669272,
+  "Oliver Zaus": 6557718111413187018,
+  "Opel Opel Hotline": -4478751528439010297,
+  "Pascal Stricker": 5092943347634680871,
+  "Patrick Haese": 6773548286871871542,
+  "Patrick Kresse": 1673127102244385862,
+  "Patrick Lang": 4978649332206482835,
+  "Paul Broich": 2789789485489122449,
+  "Paweldyk J\u00f6rn": 8430255960561008697,
+  "Peter Bichmann": 2984202696882263483,
+  "Peter Hermesmeier": 3731613377952273253,
+  "Peter H\u00fcbner": 2323859072822664392,
+  "Peter Munari": 2967604391946134187,
+  "Peter M\u00fcller": 3407097512114870910,
+  "Peter Patzelt": -8738834847324556572,
+  "Peter Penterling": 896832698162253869,
+  "Peter Reisacher": -6877551414587386152,
+  "Peter Richter": -2761859372874496778,
+  "Peter Ulrich": 4297274643286780834,
+  "Peter Wittwer": -7369531694878181290,
+  "Petra Czeczelitz": 6532561946841854769,
+  "Petra Fritzmann": 6603722567705312743,
+  "Petra Meih\u00f6fer": -3451535035244832577,
+  "Petra Migowski": -2092011270656583687,
+  "Petra Noll": -5876357548560304882,
+  "Petra Oswald": -3311943928815133806,
+  "Petra Petter": 3170096351736752243,
+  "Petra Willmeroth": 3490251892471287897,
+  "Peugeot / Citroen - Peugeot / Citroen - Hotline": 5246227697418820438,
+  "Philipp Paraguya": -2758890680067084719,
+  "Pia Dax": -3205285239172488696,
+  "Piero Lo Presti": -1122644677026063164,
+  "Pizzeria Italia": -3800543339735779147,
+  "Pizzeria La Fattoria": -4687424798272252993,
+  "Pizzeria Michelangelo": 4127029462278804095,
+  "Pizzeria Pizzeria Da Piero": -3403428756596223302,
+  "Pizzeria Pizzeria La Movida Zur Krone": -6649806112987078641,
+  "Pizzeria Zur Krone": -2510542926167319879,
+  "Pizzorante La Trinacria": -585815203458640377,
+  "Plenum IT Support Plenum IT Support Hotline": -5628186940162204377,
+  "Point Sushi": 3434871405549633949,
+  "Puhl Herr Puhl": 655543914841173017,
+  "R. Zuleger": 2753039300316311856,
+  "Raflu Raflu": 3074138931099309514,
+  "Raimund Pr\u00f6bster": -9102863309070520199,
+  "Rainer Metz": -5047155199711670664,
+  "Ralf Gl\u00f6ckner": 5338659778748486787,
+  "Ralf G\u00fcnther": 7889504799216529221,
+  "Ralf Lanninger": -1709173033882156835,
+  "Ralf Mark\u00f6tter": 1732300756744959081,
+  "Ralf Ramin": 2885076632435837777,
+  "Ralph H\u00f6hne": -3930833593642530487,
+  "Ramona Martini": -2832122567928264830,
+  "Raphael Huhn": -4617745508454574516,
+  "Rath, Peter": 5618880382598996674,
+  "Rebecca Leich": 5785679443474953257,
+  "Regina M\u00fcller": 6748639248157023784,
+  "Reinhard Heigl": 6628474716878908210,
+  "Reinhard Psotka": 4849734324414173190,
+  "Reinhold Greskamp": 4832891811824004687,
+  "Reinhold Twieling": 7903543490538032664,
+  "Renate Hofbauer": 49487787094000264,
+  "Renate Schulte": 3621339456478207268,
+  "Renault Renault Hotline (DE) (DE)": 1723001148251424891,
+  "Rene G\u00e4rtner": -426623864284430777,
+  "Riederer Riederer": 7852081402115151587,
+  "Rita Dahlhauser": 5092265268396891385,
+  "Rita M\u00fcller": 3686473137910509648,
+  "Robert Bedner": 7387380865867246647,
+  "Robert Burghard": 4396113095833013414,
+  "Robert Elser": -6941407227279235575,
+  "Robert Gorski": 3664404872293130674,
+  "Robert Heindl": 4186623017177703868,
+  "Robert Jahnke": 995723412326950243,
+  "Robert Plank": 6089656289681804238,
+  "Robert Simon": 2736839027239632036,
+  "Robert Szarvas": -8167549344144852843,
+  "Roberto Grob": 848752788596983499,
+  "Roger Lang": 6233873766451616754,
+  "Rohde Rohde": 2052009991543535813,
+  "Roland Kaiser": -1299811638439197224,
+  "Rolf Mund": -1871578311124067811,
+  "Roman Kerber": 6715734728630808487,
+  "Romy Eberwein": 3116954728320644234,
+  "Rosl Hanft": -8344385513374259616,
+  "Roy Allen": 1795052080995262104,
+  "Rudolf Trunsperger": -493829014408221156,
+  "Rumyana Avgustinova": 965129998888870854,
+  "Rupert B\u00f6rsig": -276340155304727329,
+  "R\u00fcdiger Ditz": 663824976067597864,
+  "S Dobel": 8837537482184082955,
+  "S. Klussmann": -5675335028442852229,
+  "Sabina Brandt": -6409763426971165919,
+  "Sabina Kupi": 4248780861449550257,
+  "Sabine Br\u00fcckner": -706686112946388566,
+  "Sabine Buss": 7906461929859083374,
+  "Sabine B\u00f6ttche": -168640847437483575,
+  "Sabine Groll": 6143534157362340012,
+  "Sabine Hanwalter": -3521134096787336642,
+  "Sabine Kionke": 8636984809751470363,
+  "Sabine Tilp": 6678979286608495898,
+  "Sabine Urban": -7539437867424122516,
+  "Sabine Wicenec": 522938526827802267,
+  "Sabrina Schumacher": -6656831818349156806,
+  "Sachtleber, Jan": 3720884455137788294,
+  "Samuel Hartmann": -1994916929601482737,
+  "Sandra Deverson": -2636605201765159677,
+  "Sandra G\u00fcnther": 4186230202600572530,
+  "Sarah Weingarten": -6859212389278709435,
+  "Sascha Ackermann": -6820113221914415186,
+  "Sascha Hofmann": 7676837900283415138,
+  "Sascha Lindner": -4593568092628784657,
+  "Sascha Metzger": -7566483877665856574,
+  "Schacht Schacht": 3167155577622086935,
+  "Scharat Pirzadeh": 6439123861891660624,
+  "Schierloh, Gunnar": 7713594746447385619,
+  "Schiller Monika": -1077484001733734172,
+  "Schmitz Schmitz": -3584453898939521162,
+  "Schreibwaren Hoffmann": 4438689935637516956,
+  "Schuchardt / Schuchardt / PC-Visit": -2640430184378118996,
+  "Schult Herr Schult": -7578710520139798062,
+  "Schwarz Herr Schwarz": 5445838138013531038,
+  "Sch\u00e4fer Herr Sch\u00e4fer": 8379295337201619895,
+  "Sdebik;  Sven": -2974274548791352502,
+  "Sebastian Anders": 1599205814712206839,
+  "Sebastian Gawliczek": -4250906353688206876,
+  "Sebastian Geyer": -2803694065913013510,
+  "Sebastian Henn": 3568970783835150093,
+  "Sebastian Hillebrand": -196244352247602680,
+  "Sebastian Kluge": 6525282493618603834,
+  "Sebastian Schr\u00f6der": -4329567027156296260,
+  "Sebastian Walther": 1539720105128483976,
+  "Shobana Ramanathan": -2645973587112307980,
+  "Sick Sick": 1439522020947058767,
+  "Siegfried Eberhardt": 1496997708336669981,
+  "Silke Keinert": -1919329375101734245,
+  "Silke M\u00fcller": -6011042272947450039,
+  "Silvia B\u00f6rner": -2217765911690133722,
+  "Silvia Schwalb-Fischer": 6868534749338576024,
+  "Silvio Schubert": -4728411702967963881,
+  "Simon Kessler": 6788647025755031069,
+  "Simon Untiet": -7857406808251454842,
+  "Simone Erlemann-Birke": -123648452308838047,
+  "Simone Neulinger": -9101304127331963803,
+  "Skoda Skoda Hotline": 5557895307752141354,
+  "Sofra Kebap Haus": -6699266556632633169,
+  "Sondermann Sondermann": -6962451351448263645,
+  "Sonja Glade": 2437525198325012762,
+  "Sonja Reitmeyer": -1746141079265855520,
+  "Stefan Adler": 783876075555260489,
+  "Stefan Aretz": 699086591256693175,
+  "Stefan Baumgartner": 944421014806177997,
+  "Stefan Colisi": 3166051755243498047,
+  "Stefan Drechsel": -1482145164983871996,
+  "Stefan Fischer": -6895953694608571980,
+  "Stefan Flick": 6357477867878192270,
+  "Stefan Freiboth": -4875176046718896490,
+  "Stefan Fricke": -6395089088555227956,
+  "Stefan Gabriel": 5787636579608626089,
+  "Stefan Hegewald": -4045162012788430604,
+  "Stefan Kaiser": 6510538998344770939,
+  "Stefan Koch": 2622606375760884347,
+  "Stefan Pollach": 4396566492955860597,
+  "Stefan Pollok": 301529740139766908,
+  "Stefan Pukall": -7380635937362795298,
+  "Stefan Rellmann": -6131469708155364218,
+  "Stefan Rockenschaub": -6912283167816677820,
+  "Stefan Schwarz": -1372376839450847374,
+  "Stefan Sch\u00e4fer": -664369514290859932,
+  "Stefan Statzengruber": -2220657196934154983,
+  "Stefan Stecher": 7712654976170099253,
+  "Stefan Welter": -188827566994329491,
+  "Stefanie Fricke": -3749721437284228149,
+  "Stefanie Kopp": -594161958990753060,
+  "Stefanie Neulinger": 490896426644610715,
+  "Stefanie Rei\u00df (Vertretung Dallmann)": -4190134063960843264,
+  "Stefanie Wolkenhaar": -1468730906737611872,
+  "Steffen Degenhardt": -4712319481685486038,
+  "Steffen G\u00fcnther": -5522234211297037556,
+  "Steffen Kowalewski": -6931971614647192674,
+  "Steffen R\u00fcger": -7324816583602422954,
+  "Stephan Jackowski": 8849321750668566868,
+  "Stephan Reiterits": 6103730177975036323,
+  "Stephan Schmidthals": -578715740733568729,
+  "Stephanie Stangohr": -2073610643007419518,
+  "Stffen Reuter": -2868440400237726026,
+  "Strobel Agnes": -840394206774379076,
+  "Support Awork": -7661131878013700801,
+  "Susanne G\u00fcnter-Uyar": 5105662876431140295,
+  "Sven Gr\u00fcllmeyer": 578526697151783117,
+  "Sven Potrafke": 1408399014379022584,
+  "Sven Springer": -2311216126040610836,
+  "Sven Weber": 5673234617379349153,
+  "Sylvia Dreber": 6904667441494456567,
+  "Sylvia Richwien": -7924481018983442424,
+  "Sylvia Weichselbaum": 3275587183689812309,
+  "S\u00f8ren Hvass": -6761042566001341735,
+  "Tanja Mildhammer": -1556251093962356473,
+  "Tanja Riede": 7903858400970238772,
+  "Tayfun Tunaboylu": -2373948981633145186,
+  "Telekom Teams UCC": 2118558777300437868,
+  "Theodor Schulte (IT)": 2668624050683393551,
+  "Theresa Meyer": 8208230483796267322,
+  "Thomas Berger": -342668014342904703,
+  "Thomas Beringhoff": -6233061237490702536,
+  "Thomas Burkard": 7665624847595915937,
+  "Thomas Denz": 867338870540756588,
+  "Thomas Doll": -7537044719058898534,
+  "Thomas F\u00e4rber": -5307650210553500631,
+  "Thomas G\u00fcrntke": 1922937388799039224,
+  "Thomas Hornung": 3016419516909013111,
+  "Thomas Huber": 1973060058295707744,
+  "Thomas H\u00e4nisch": -5707370785022121461,
+  "Thomas Liegert": -6285880117920051198,
+  "Thomas L\u00fcbbertsmeier": -6659757293061634107,
+  "Thomas Mundt": 392138002778414306,
+  "Thomas M\u00fcller": 7278964020053244891,
+  "Thomas Schwarz": 5798790803476227109,
+  "Thomas Thiele": -46044147152403315,
+  "Thomas Timmermanns": 77458437292870335,
+  "Thomas Wassermann": -8671399743914530585,
+  "Thomas Weisner": 4228489819101217141,
+  "Thomas Werthmann": 4626361254076640968,
+  "Thomas W\u00e4chter": 1143037778476779389,
+  "Thorsten Bentners": -381117258279420440,
+  "Th\u00fcmmler Herr Th\u00fcmmler": 8059762993779445383,
+  "Tim Kastenholz": -8455207874473352122,
+  "Timo Sattler": 7060864734139125482,
+  "Tina Reisacher": -3728914836155195104,
+  "Tina Winkler": 3209543469936680693,
+  "Tobias Althausse": 3847003662225922744,
+  "Tobias Degelmann": 2734894878645301239,
+  "Tobias K\u00f6ppel": 5985409179361567283,
+  "Tobias Pfeifer": -4039050058597690848,
+  "Tom Hoefler": -3283936506736825475,
+  "Toni": 5546971687049632443,
+  "Torsten Kaiser": -7942814233014534145,
+  "Torsten Zobjack": -6463350645494696417,
+  "Traute Gei\u00df": -7933492436721015909,
+  "Udo J\u00fcrgenlohmann": -6459642628361189836,
+  "Udo Sonnenberg / PC-Visit": 5860303336716452148,
+  "Ulf Schwabe": -3626406681342695977,
+  "Ulf Wagner": 356894194119029970,
+  "Uli Vinkelau": 2590930067056013287,
+  "Ulla Roscher-Geu\u00df": 5771678491071205222,
+  "Ulrich K\u00fcchler": -3458275325214594707,
+  "Ulrich Nothof": 1275342180899564584,
+  "Ulrich Sikorski": 2872370595125987632,
+  "Ulrike Aull": 1269858612412733870,
+  "Urban Science Urban Science Hyundai": 6513682790999328925,
+  "Ute Dietmann": -2541787131949305351,
+  "Uwe Gewald": 7097439176651023776,
+  "Uwe Heinz": 4487222449263812128,
+  "VW/Seat Hotline - Urban VW/Seat Hotline - Urban Science": 7593564506669767993,
+  "Vanessa Malzer": -7667532871570095597,
+  "Vanessa Schwager": 6352198089358492310,
+  "Vera K\u00f6hler": -7313904547720855528,
+  "Verena Wolff": -8027147356677319200,
+  "Veronika Seitlinger": -5990944757177007393,
+  "Victor Schneider": 2441565914129327428,
+  "Vodafone Globalcube": -1584363496905051043,
+  "Volker Lohs": 6500702491085018974,
+  "Wach- und Schlie\u00dfdienst BWS": 3649869366558253958,
+  "Webels Webels": -106833271084036488,
+  "Weger Herr Weger": -7607911723224322302,
+  "Welz Dirk": -8664084584774983148,
+  "Werner Blum": -4298447829460816767,
+  "Werner H\u00f6fer": -7084630700394772899,
+  "Wiepke Lippitsch": 460580108507593286,
+  "Wiesner, Christine": 5127233862926274617,
+  "Wietmann Wietmann": -6370441306158330592,
+  "Wilfried Opitz": 4849235514473428520,
+  "Wilhelm Jonas": -1382690932512018620,
+  "Wilhelm Wolf": -2784033125277403887,
+  "Willi Meures": -3853534092280736922,
+  "Winfried Winkler": 4745553329079743116,
+  "Winskowski Herr Winskowski": 2136040761779003410,
+  "Winter Herr Winter": 8718233218291697432,
+  "Winter Winter": 2861096377170295468,
+  "Winzmann Winzmann": -2786569430553220466,
+  "Wolfgang Hicke": -7124561036743503144,
+  "Wolfgang Schwentner": 5691119379502484313,
+  "Wolfgang Wallner": 5393958801685519895,
+  "Wolfram Weber": 8707430284524765274,
+  "Wolgang Bac": -5479482411891492127,
+  "W\u00fcnsche Herr W\u00fcnsche": 6762360202969268394,
+  "Yonca Sezer": -4781998807899075232,
+  "Yvonne Ammon": -7784302622186628321,
+  "Yvonne R\u00fcping": 4335219653767820011,
+  "Zentrale CDK": -1689395691033682529,
+  "Zentrale Dietrich": -7873758297975969591,
+  "Zentrale Freicon": 2950730358152004009,
+  "Zentrale Greiner": 7425005640465656663,
+  "Zentrale Karl Asbach GmbH": 4090309627430093216,
+  "Zentrale La Linea": 6938164545918739706,
+  "Zentrale MGS": -2541974624486634301,
+  "Zentrale M\u00fcller Mainz": -6931601705563370971,
+  "Zentrale Nauheim": -7895995612453761445,
+  "Zentrale Sch\u00f6ntges": -2826378629643862809,
+  "Zimmer Zimmer": 4541121242216237591,
+  "abc def": -6540831068220412953
+}

+ 240 - 20
contacts/o365_copy.py

@@ -1,5 +1,15 @@
+import dataclasses
+import json
+from pathlib import Path
+from typing import Self
+
+import jinja2
+import typer
 from O365 import Account
 from O365.address_book import Contact
+from smtp_mail import SmtpMailer
+
+app = typer.Typer()
 
 client_id = "925f74dc-f96a-4718-9ca7-d6cc3fa43e1e"
 client_secret = "SMn8Q~rVUnbYEAtEZZ6jcQElOIU9tDQUgv1VwcRz"
@@ -20,6 +30,93 @@ mailboxes = [
     "karaca@global-cube.net",
 ]
 
+base_dir = Path(__file__).parent / "data"
+
+
+class EnhancedJSONEncoder(json.JSONEncoder):
+    def default(self, o):
+        if dataclasses.is_dataclass(o):
+            return dataclasses.asdict(o)
+        return super().default(o)
+
+
+@dataclasses.dataclass
+class SerialEmail:
+    address: str
+    name: str
+
+
+@dataclasses.dataclass
+class SerialContact:
+    display_name: str
+    name: str
+    surname: str
+    title: str
+    job_title: str
+    company_name: str
+    department: str
+    office_location: str
+    business_phones: str
+    mobile_phone: str
+    home_phones: str
+    emails: list[SerialEmail]
+    business_address: str
+    other_address: str
+    categories: str
+    personal_notes: str
+
+    def __lt__(self, other):
+        return self.display_name < other.display_name
+
+    def __eq__(self, other):
+        return self.display_name == other.display_name
+
+    @staticmethod
+    def from_o365_contact(p_from: Contact) -> Self:
+        return SerialContact(
+            display_name=p_from.display_name,
+            name=p_from.name,
+            surname=p_from.surname,
+            title=p_from.title,
+            job_title=p_from.job_title,
+            company_name=p_from.company_name,
+            department=p_from.department,
+            office_location=p_from.office_location,
+            business_phones=p_from.business_phones,
+            mobile_phone=p_from.mobile_phone,
+            home_phones=p_from.home_phones,
+            emails=[SerialEmail(e.address, e.name) for e in p_from.emails],
+            business_address=p_from.business_address,
+            other_address=p_from.other_address,
+            categories=p_from.categories,
+            personal_notes=p_from.personal_notes,
+        )
+
+    def __hash__(self) -> int:
+        return hash(json.dumps(dataclasses.asdict(self)))
+
+    def to_o365_contact(self, p_to: Contact):
+        p_to.display_name = self.display_name
+        p_to.name = self.name
+        p_to.surname = self.surname
+        p_to.title = self.title
+        p_to.job_title = self.job_title
+        p_to.company_name = self.company_name
+        p_to.department = self.department
+        p_to.office_location = self.office_location
+        p_to.business_phones = self.business_phones
+        p_to.mobile_phone = self.mobile_phone
+        p_to.home_phones = self.home_phones
+        p_to.emails.clear()
+        for rcp in self.emails:
+            p_to.emails.add(rcp)
+        p_to.business_address = self.business_address
+        # p_to.home_address = self.home_address
+        p_to.other_address = self.other_address
+        p_to.categories = self.categories
+        p_to.personal_notes = self.personal_notes
+        return p_to
+
 
 def copy_contact(p_from: Contact, p_to: Contact):
     p_to.display_name = p_from.display_name
@@ -44,32 +141,75 @@ def copy_contact(p_from: Contact, p_to: Contact):
     p_to.save()
 
 
+@app.command()
 def sync_contacts():
     account.authenticate()
     shared = account.address_book(resource="adressbuch@global-cube.net", address_book="personal")
     shared_contacts = {p.display_name: p for p in shared.get_contacts(limit=None)}
+    shared_contacts_serial = [SerialContact.from_o365_contact(p) for p in shared_contacts.values()]
+    shared_contacts_serial.sort()
+    json.dump(shared_contacts_serial, (base_dir / "shared.json").open("w"), indent=2, cls=EnhancedJSONEncoder)
+    shared_contacts_hash = {c.display_name: hash(c) for c in shared_contacts_serial}
+    shared_contacts_prev = json.load((base_dir / "shared_hash.json").open("r"))
+
     delete_candidates = set()
 
     for mailbox in mailboxes:
         print(mailbox)
+        mailbox_prefix = mailbox.split("@")[0]
         personal = account.address_book(resource=mailbox, address_book="personal")
         personal_contacts = {p.display_name: p for p in personal.get_contacts(limit=None)}
+        personal_contacts_serial = [SerialContact.from_o365_contact(p) for p in personal_contacts.values()]
+        personal_contacts_serial.sort()
+        personal_contacts_hash = {c.display_name: hash(c) for c in personal_contacts_serial}
+
         extra_contacts = set(personal_contacts.keys()).difference(shared_contacts.keys())
+        extra_contacts_serial = [SerialContact.from_o365_contact(personal_contacts[c]) for c in extra_contacts]
+        extra_contacts_serial.sort()
+        json.dump(
+            extra_contacts_serial,
+            (base_dir / f"personal_{mailbox_prefix}_extra.json").open("w"),
+            indent=2,
+            cls=EnhancedJSONEncoder,
+        )
         print(extra_contacts)
+        different_contacts = []
         if len(delete_candidates) == 0:
             delete_candidates = extra_contacts
         else:
             delete_candidates = delete_candidates.intersection(extra_contacts)
-        # p.delete()
 
         for p_shared in shared_contacts.values():
             if p_shared.display_name not in personal_contacts:
                 p_new = personal.new_contact()
                 copy_contact(p_shared, p_new)
-            else:
-                p_existing = personal_contacts[p_shared.display_name]
-                if p_existing.to_api_data() != p_shared.to_api_data():
-                    copy_contact(p_shared, p_existing)
+                continue
+            if personal_contacts_hash[p_shared.display_name] == shared_contacts_hash[p_shared.display_name]:
+                # contact details are identical, nothing to do
+                continue
+            if personal_contacts_hash[p_shared.display_name] == shared_contacts_prev[p_shared.display_name]:
+                # simply update contact details
+                copy_contact(p_shared, personal_contacts[p_shared.display_name])
+                continue
+            different_contacts.append(SerialContact.from_o365_contact(personal_contacts[p_shared.display_name]))
+
+        different_contacts.sort()
+        json.dump(
+            different_contacts,
+            (base_dir / f"personal_{mailbox_prefix}_diff.json").open("w"),
+            indent=2,
+            cls=EnhancedJSONEncoder,
+        )
+        different_contacts_shared = [
+            SerialContact.from_o365_contact(shared_contacts[c.display_name]) for c in different_contacts
+        ]
+        json.dump(
+            different_contacts_shared,
+            (base_dir / f"shared_{mailbox_prefix}_diff.json").open("w"),
+            indent=2,
+            cls=EnhancedJSONEncoder,
+        )
+    json.dump(shared_contacts_hash, (base_dir / "shared_hash.json").open("w"), indent=2, cls=EnhancedJSONEncoder)
     return delete_candidates
 
 
@@ -89,7 +229,7 @@ def delete_contacts(delete_candidates):
 
 def normalize_phone_number(phone_number: str):
     if phone_number is None:
-        return None
+        return ""
     if phone_number.startswith("0"):
         phone_number = "+49 " + phone_number[1:]
     for c in "()/?":
@@ -99,23 +239,103 @@ def normalize_phone_number(phone_number: str):
 
 def cleanup_contacts():
     account.authenticate()
-    shared = account.address_book(resource="adressbuch@global-cube.net", address_book="personal")
 
-    for p in shared.get_contacts(limit=None):
-        business = [normalize_phone_number(no) for no in p.business_phones]
-        if p.business_phones != business:
-            p.business_phones = business
-        home = [normalize_phone_number(no) for no in p.home_phones]
-        if p.home_phones != home:
-            p.home_phones = home
-        mobile = normalize_phone_number(p.mobile_phone)
-        if p.mobile_phone != mobile:
-            p.mobile_phone = mobile
-        p.save()
+    for mailbox in mailboxes:
+        print(mailbox)
+        shared = account.address_book(resource=mailbox, address_book="personal")
 
+        for p in shared.get_contacts(limit=None):
+            business = [normalize_phone_number(no) for no in p.business_phones]
+            if p.business_phones != business:
+                p.business_phones = business
+            home = [normalize_phone_number(no) for no in p.home_phones]
+            if p.home_phones != home:
+                p.home_phones = home
+            mobile = normalize_phone_number(p.mobile_phone)
+            if p.mobile_phone != mobile:
+                p.mobile_phone = mobile
+            if p._track_changes:
+                print(p.display_name)
+                p.save()
 
-if __name__ == "__main__":
+
+def cleanup_contacts2():
+    account.authenticate()
+
+    for mailbox in mailboxes:
+        print(mailbox)
+        personal = account.address_book(resource=mailbox, address_book="personal")
+
+        for p in personal.get_contacts(limit=None):
+            if not p.mobile_phone:
+                p.mobile_phone = ""
+            if not p.job_title:
+                p.job_title = ""
+            if not p.department:
+                p.department = ""
+            if not p.office_location:
+                p.office_location = ""
+            p.save()
+
+
+def cleanup_contacts3():
+    account.authenticate()
+
+    for mailbox in mailboxes:
+        print(mailbox)
+        personal = account.address_book(resource=mailbox, address_book="personal")
+
+        for p in personal.get_contacts(limit=None):
+            if p.display_name is None or p.display_name == "":
+                print(p.name, p.surname)
+
+
+def create_private_folder():
+    account.authenticate()
+
+    for mailbox in mailboxes:
+        print(mailbox)
+        personal = account.address_book(resource=mailbox, address_book="personal")
+
+        private = personal.get_folder(folder_name="privat")
+        if private is None:
+            personal.create_child_folder("privat")
+
+
+@app.command()
+def send_mail():
+    account.authenticate()
+    # mailboxes2 = ["bedner@global-cube.net"]
+
+    with open(base_dir / "../templates/info.html.jinja") as f:
+        template = jinja2.Template(f.read())
+
+    for mailbox in mailboxes:
+        mailbox_prefix = mailbox.split("@")[0]
+        extra_contacts = json.load((base_dir / f"personal_{mailbox_prefix}_extra.json").open("r"))
+        different_contacts = json.load((base_dir / f"personal_{mailbox_prefix}_diff.json").open("r"))
+
+        with SmtpMailer() as mailer:
+            mailer.send(
+                mailto=mailbox,
+                subject="Wochenbericht adressbuch@global-cube.net",
+                html=template.render(extra_contacts=extra_contacts, different_contacts=different_contacts),
+                attachment=[
+                    ("privat.json", (base_dir / f"personal_{mailbox_prefix}_diff.json")),
+                    ("geteilt.json", (base_dir / f"shared_{mailbox_prefix}_diff.json")),
+                ],
+            )
+
+
+@app.command()
+def sync_and_delete():
     contacts = sync_contacts()
     if len(contacts) > 0:
         delete_contacts(contacts)
-    # cleanup_contacts()
+
+
+if __name__ == "__main__":
+    # create_private_folder()
+    # send_mail()
+    # cleanup_contacts3()
+    app()

+ 111 - 0
contacts/smtp_mail.py

@@ -0,0 +1,111 @@
+import smtplib
+import ssl
+from dataclasses import dataclass
+from email.mime.application import MIMEApplication
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+from email.utils import make_msgid
+from pathlib import Path
+
+
+@dataclass
+class MailConfig:
+    server: str
+    port: int
+    secure: str
+    username: str
+    password: str
+    email: str
+
+
+@dataclass
+class Message:
+    mailto: str
+    subject: str
+    html: str
+    attachment: list
+
+
+class SmtpMailer:
+    connected = False
+
+    def __init__(self, cfg=None):
+        if cfg is None:
+            cfg = default_cfg
+        self.mail_cfg = cfg
+        self.reply_to = "versand@global-cube.com"
+        self.context = ssl.create_default_context()
+
+    def __enter__(self):
+        try:
+            if self.mail_cfg.secure == "ssl":
+                self.mailserver = smtplib.SMTP_SSL(self.mail_cfg.server, self.mail_cfg.port, context=self.context)
+            else:
+                self.mailserver = smtplib.SMTP(self.mail_cfg.server, self.mail_cfg.port)
+
+            if self.mail_cfg.secure == "tls":
+                self.context.minimum_version = ssl.TLSVersion["TLSv1_2"]
+                self.mailserver.ehlo()
+                self.mailserver.starttls(context=self.context)
+
+            self.mailserver.login(self.mail_cfg.username, self.mail_cfg.password)
+            self.connected = True
+        except smtplib.SMTPException as e:
+            print(e)
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        if self.connected:
+            self.mailserver.quit()
+
+    def send(self, mailto, subject, html, attachment=None):
+        msg = self.message(mailto, subject, html, attachment)
+        msg["Message-ID"] = make_msgid(domain=self.mail_cfg.server)
+        # res = {"id": msg["Message-ID"], "mailto": mailto, "status": "OK"}
+
+        try:
+            self.mailserver.sendmail(self.mail_cfg.email, mailto, msg.as_string())
+        except smtplib.SMTPException as e:
+            print(e)
+            pass
+
+    def message(self, mailto, subject, html, attachment):
+        msg = MIMEMultipart("alternative")
+        msg["From"] = self.mail_cfg.email
+        msg["To"] = mailto
+        msg["Subject"] = subject
+
+        msg.attach(MIMEText(html, "html"))
+
+        for name, filename in attachment or []:
+            with open(filename, "rb") as f:
+                part = MIMEApplication(f.read(), Name=name)
+                part["Content-Disposition"] = f'attachment; filename="{name}"'
+                msg.attach(part)
+        return msg
+
+
+default_cfg = MailConfig(
+    server="mail.global-cube.com",
+    port=465,
+    secure="ssl",
+    username="versand",
+    password="y6!avXX3tQvr",
+    email="versand@global-cube.com",
+)
+
+if __name__ == "__main__":
+    base_dir = str(Path(__file__).parent.parent)
+
+    with SmtpMailer() as m:
+        m.send(
+            "robert.bedner@gmail.com",
+            "Test 1234567",
+            "kein Kommentar",
+            [
+                (
+                    "Umsatz_Bruttoertrag_Aftersales.pdf",
+                    base_dir + "/Portal/Publish/daten/gaps_vers_tag/Umsatz_Bruttoertrag_Aftersales_0.pdf",
+                )
+            ],
+        )

+ 35 - 0
contacts/templates/info.html.jinja

@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <h1>Wochenbericht</h1>
+    <h2>Zusätzliche Kontakte</h2>
+    <p>Folgende Kontakte hast du in deinem persönlichen Adressbuch, aber nicht im geteilten Adressbuch.
+    <p>Falls diese Kontakte tatsächlich privat sind, kannst du diese in den Unterordner "privat" verschieben.
+    <p>Wenn du diese Kontakte nicht mehr benötigst oder die Kontakte versehentlich doppelt angelegt sind, 
+    kannst du sie einfach löschen.
+    <p>Wenn du diese Kontakte mit dem Team teilen möchtest, verschiebe sie in das geteilte Adressbuch. 
+    (In Outlook: Kontakte - Global Cube)
+    <ul>
+    {% for c in extra_contacts %}
+      <li>"{{ c.display_name }}"</li>
+    {% else %}
+      <li>Keine zusätzlichen Kontakte gefunden.</li>
+    {% endfor %}
+    </ul>
+    <p>&nbsp;</p>
+    <h2>Abweichende Kontakte</h2>
+    <p>Folgende Kontakte sind in deinem persönlichen Adressbuch, aber auch im geteilten Adressbuch vorhanden.
+    <p>Sie unterscheiden sich in mindestens einem Detail.
+    <p>Überprüfe, ob diese Kontakte korrekt sind und passe sie im geteilten Adressbuch an.
+    <p>Lösche im Anschluss den Eintrag in deinem persönlichen Adressbuch. 
+    Der Kontakt wird mit der nächsten Synchronisation wieder neu geschrieben und ist ab dann wieder synchron.
+    <ul>
+    {% for c in different_contacts %}
+      <li>"{{ c.display_name }}"</li>
+    {% else %}
+      <li>Keine abweichenden Kontakte gefunden.</li>
+    {% endfor %}
+    </ul>
+    <p>Details zu den Abweichungen findest du im Anhang.
+  </body>
+</html>

+ 2 - 0
requirements.txt

@@ -7,6 +7,7 @@ Flask_Cors
 imap_tools
 Jinja2
 numpy
+O365
 oauthlib
 openpyxl
 pandas
@@ -22,6 +23,7 @@ requests
 requests_oauthlib
 schedule
 SQLAlchemy
+typer
 unlzw
 uptime
 xlrd