auf dot_env umgestellt

This commit is contained in:
2026-05-31 09:16:04 +02:00
parent 54e6daee09
commit 241020f9a8
9 changed files with 502 additions and 462 deletions
+12
View File
@@ -0,0 +1,12 @@
IMAP_HOST=imap.mailbox.org
IMAP_PORT=993
IMAP_USERNAME=minitux@mailbox.org
IMAP_PASSWORD=4711Cayenne64
IMAP_FOLDER=INBOX
IMAP_UNSEEN_ONLY=true
IMAP_MARK_AS_READ=false
CALDAV_URL=https://dav.mailbox.org/caldav/Y2FsOi8vMC8zMg
CALDAV_USERNAME=minitux@mailbox.org
CALDAV_PASSWORD=4711Cayenne64
+11
View File
@@ -0,0 +1,11 @@
IMAP_HOST=imap.mailbox.org
IMAP_PORT=993
IMAP_USERNAME=ihr-name@mailbox.org
IMAP_PASSWORD=IHR_PASSWORT_ODER_APP_PASSWORT
IMAP_FOLDER=INBOX
IMAP_UNSEEN_ONLY=true
IMAP_MARK_AS_READ=false
CALDAV_URL=https://dav.mailbox.org/caldav/IHR_KALENDER_ID
CALDAV_USERNAME=ihr-name@mailbox.org
CALDAV_PASSWORD=IHR_PASSWORT_ODER_APP_PASSWORT
+1
View File
@@ -6,6 +6,7 @@ name = "pypi"
[packages] [packages]
caldav = "*" caldav = "*"
icalendar = "*" icalendar = "*"
python-dotenv = "*"
[dev-packages] [dev-packages]
Generated
+270 -261
View File
@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "9054d163ae11d3340046ee5035c05385631e1acc0c9d054a174ef809369b6c78" "sha256": "3a457d8118e1aff25d23511f86d5f9e7939f91893ea824178ed850203ecbc74c"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@@ -18,12 +18,12 @@
"default": { "default": {
"caldav": { "caldav": {
"hashes": [ "hashes": [
"sha256:39361f460a96599b8e4efbbdd711382adb1bbe8fc278eac4650f23cb6155eca5", "sha256:6869e505ad14741a582003c93e49be2689013d19c9b91679c7c385775b673408",
"sha256:d4df2c73843162af2fe7d324149830de8903690bfa094244029481d9bba320d0" "sha256:b474900130226f22dbe3e3abed34559faaeed8a29c455af920c2afb0e355e3d3"
], ],
"index": "pypi", "index": "pypi",
"markers": "python_version >= '3.10'", "markers": "python_version >= '3.10'",
"version": "==3.2.0" "version": "==3.2.1"
}, },
"charset-normalizer": { "charset-normalizer": {
"hashes": [ "hashes": [
@@ -162,11 +162,11 @@
}, },
"click": { "click": {
"hashes": [ "hashes": [
"sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2",
"sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613" "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"
], ],
"markers": "python_version >= '3.10'", "markers": "python_version >= '3.10'",
"version": "==8.3.3" "version": "==8.4.1"
}, },
"dnspython": { "dnspython": {
"hashes": [ "hashes": [
@@ -186,272 +186,272 @@
}, },
"icalendar": { "icalendar": {
"hashes": [ "hashes": [
"sha256:10cd223c792fcc43bee4c3ebe3149d4cf32406c85cfef146624df5a0d414260f", "sha256:01c76243c76c549f58bb51510a8f0a4edb7c539726adda1356dfd0dc04fb7a53",
"sha256:6de875370d22fc4aff172ad7c439b39fb109dc2eab9ce358fcb95e8689ad7b56" "sha256:ebc43ebeb357be98984b573d975118008dee3410d8df28b054ef2943cf3e367e"
], ],
"index": "pypi", "index": "pypi",
"markers": "python_version >= '3.10'", "markers": "python_version >= '3.10'",
"version": "==7.1.0" "version": "==7.1.2"
}, },
"icalendar-searcher": { "icalendar-searcher": {
"hashes": [ "hashes": [
"sha256:66f6f5ece50041ceda5ea91995cd2ed80fa0b065a42b3b3f420f89343614b2a3", "sha256:2440d4d0d9fbe0021a6647916853744dbca179abd39d25c742ebb8442bbc1bc3",
"sha256:abd99bf1ac9c9d675d84151101db4883a97e9958755708804c55abd30df58f6c" "sha256:649aad558df211bc50ca3dea3646e1b2f3e93f0995bca2b6358e9c79031471b6"
], ],
"markers": "python_version >= '3.10' and python_version < '4.0'", "markers": "python_version >= '3.10' and python_version < '4.0'",
"version": "==1.0.5" "version": "==1.0.6"
}, },
"jh2": { "jh2": {
"hashes": [ "hashes": [
"sha256:05102a4610dde1dc59c630e64ca34a74076d1afd275dbeac954b230a605788b9", "sha256:020abf569e05cf807104b4a8b43ef26ab4684fd7d26441791a2b9f450a01c66d",
"sha256:070adb3943f306257fff6dff4cbdcb5324afd78cbfa624f6686f198e6381d707", "sha256:03c1ba7cbebb2e3be1ea62b789d2caab907288ec5f11c97e190ea71bd640878d",
"sha256:08392b71819ef4dec683010b0366b15da8ed495250110c6009833f25855ab6a4", "sha256:05849bda038c2f8cee50559e3fd363af39c80fb1f24ecf947ccbc7e1a890683f",
"sha256:148195763588b0b8003fc365783838fabdc8450346b7c8df0c7945b80f252fab", "sha256:0ad4d68340e38a8474a48c424e2929d3e2e82e35e4e8ff1188decb1985d1b4d7",
"sha256:1517147850dd3bcf8e3204e7e4b4016e47440a889accfd6b055734dd2686bc89", "sha256:0ee6a5dd24a1dc0772a89b3498ed20f60167fbc633404b1e02895f04ae66c47c",
"sha256:176f4de35aef5f3eef38d6ae785bb530f911af1fc6a21512da620250cde95a94", "sha256:194537a1f6d06322448f65b72726014f7a31a484325db5aa30795a670b47d7f9",
"sha256:18f10dcf0aa9f19833ac0f4d58b195af2d0b056423d428f74bf03f7839db8055", "sha256:1a75eed545420a31ea356e8046b8d86fcf694234dd1035191734a03720fb8a44",
"sha256:264b93edeb9368cd4ad8b8ba4a23e9404ba6a449ded00f6c1e62b259fabf43c8", "sha256:1a84ca3b2cf786a811a828d68d8f3b4587566f7e8236a2c42a77443157eb6053",
"sha256:27ab9efb8127d1dce11fb6f12cc4ab4339338cf66bb758734ee3e5e7937cf11a", "sha256:1dd137086b13d55a53c4b7b8b75869c824060a4d35615e4f49180ae58c7783f5",
"sha256:2b7daf269b477e22beedc6767e471a72a3fc988538ad295b80dafceb289f3dc2", "sha256:1f3994201495621bac0d1aff8b5ca9a5f185b91b64638e026d9c94584fdd795f",
"sha256:2d7e43c6248e3a091e9f6c5aac23236bd7ba0e30d240f4017b644bd3da049688", "sha256:1f4dffe1c6ed0d4b0d2d9a45d064622bb786cbf87db35eac469dd4c376ac6fb6",
"sha256:2f88407c7d2de429346e589ede8f0eaa594d6a8a3e388b658bbf4828998a53a0", "sha256:2110e32bde0765fce8a52ec4d51b5ebe1d679de862a1da34f67d887acbdf390d",
"sha256:31d5c24cc3c20b49ad00e25e2d429d51b240a7f7fc8910c48a1fa11cf84f0c71", "sha256:2195557f5953ceee743d0eaab0b09ec537bbc1b9a2c6c1463106bfca9b03805f",
"sha256:31ddace327ac78b3137d79c4ce1a64fb8d5b1256a88078e7806b20280a22ed1c", "sha256:267aaa7a96f54452e1e07c7701799bc7817e1f3bb2de09301b2c492841e4c98e",
"sha256:34c0bbf4688917a3a1b1dba176bc49bb5b1ad4b75765431b989f7767061df432", "sha256:28cb7c8d9fa0cdb3d357776ad82312c6ced6481fc828f898a04419933c0532d5",
"sha256:3581858d586d0dc87bfb47c3446b67dbbbe5f26a0c4aab94bc0f88d9329a4101", "sha256:296ee44dfad08ccc3857daf433dfa4a555d5b45f2df39503ccdd90ff10b32943",
"sha256:37ecb9da2bbc590753593220a80b2c24d7e8411238bad2d1e331e5c2287bb3d1", "sha256:29c23f3937f257beb5cd5b17f8727404f1267ff25d26e54c0a35d5defd0c895e",
"sha256:3c3b06db73cde4e350e8acd5960e6bd9880e512cc8ab9c28003c74414261382b", "sha256:2a37164eb8f2462268e6252db93b009cb685fa060b62ad217bf1b333b450c68d",
"sha256:3dea67e8ae492168e4271351dca8869e4bf79f3bb45d301d54f9639e8cb345ae", "sha256:2b311414989da48a155721fe47d0dc3e3b75360efd62d779aaff72d786be91cf",
"sha256:3ebfcd80cfcaa17bbb5733871953d1df79e1cc8bdc0f22d7372d9f2ef3524008", "sha256:2cc4923ac6f57753e0cb4aef054a04f5d5c744b274dabf863f695fa3c2fd75f9",
"sha256:4aa8c32df2426f7a9d8633c2c8b5555edcace6e703640cb50f7ecb5732d9b50c", "sha256:30996200b243c6dd8c176537b7b75a5d4cd910f2be6f7be9e3b12e03a39a0d9a",
"sha256:4dc82aee3ab2c4103f3d9092f4463dd6cc4a248ab6a27a4acab79bef0d3ac8dd", "sha256:31fec2270a204669fd5183465e3ef6a666a0539af61bf8e995df91f16c945c0b",
"sha256:52f5c68a736f8f70e9b4f55e9678a5f12b203f244182d261d6ffe8b239ab08f0", "sha256:3ad0a4909501bcd8b063d8757a650228ece9ac7f4b3df0363108989ab71c124c",
"sha256:5457b5bf89391cd21ab6cd051c2c1e2d78ee9507b2af473841ae5fafcc5bf048", "sha256:3e2789ac441df896333e19dce716987ab3bdbd31d15b885960e52fd8b1bb40f6",
"sha256:550831792b78e547ad7510c62db98e4feb3c0df4002ac1fd9e9b0e30903bc159", "sha256:3e5e73bbfcf0690561a1e2bf8b2d8f1e0bfd1aca67ebbed2a753cf9440f912ef",
"sha256:558d4c15bc42419262ef15595d9c488ae53276b562397314e1cc934f4c7e4bdf", "sha256:3f54095cde010ff4e52f23dda92b31d3d3160c64f5f23fc6e181f8c7938afd33",
"sha256:559c5ff8034ce36aa7c24c6acb80d4dc2a377ff552ff5c58be6d8762ed8ee048", "sha256:3f74dad9036e599eed51576492b00955237b86cf886f96844708a81cd0f5c710",
"sha256:57601fd1c5f6fce9e63ea1f2a61f83784478cf4d58e8491a7c18cc05abdb8e96", "sha256:3f8c5e81254b986f8abe9fd974e7ed595aeaead3f3066ce9ed95dfff236ceca9",
"sha256:58f4c9da6555923f731e358d975e40d4ae6241c05b29e5a0f4dc8c91781cc229", "sha256:3ff9abf4b4769c9c8117d929f87c90415cb65f54faa22f64fbf044427127e65f",
"sha256:5d6a1000872f99a2d50316bdab7dcb8a9eccebd1c7ca4ba2e656a74ee48015ac", "sha256:40d0a10036cdf8bf1a36b07c10b69ad0d08ce31d99b8962e3d055ee417fe3423",
"sha256:60c7dc47084ff8d8fe98c7d8e4be6109d861045953a9f2036d791e6d72a7e1db", "sha256:47d3203ed6fec39df4922764817979fad3a13d22cf750adc9cf9dc2b3399eacf",
"sha256:611c474b2c998fb09f5825dbe88626cc86c991a6d7dbc4c0d2a0848fa2fa437d", "sha256:4812710810010c428db04e9290a13117f7b7c5a3a663b46a0586fe101cf25c9d",
"sha256:63190c909647ec4a5c8718ea8ef89230a1f33ec6588f93cb42555065f210ef87", "sha256:49531e0042b3a4d35d34ddb892bb734d77969c9b787e6f2f0253cb10b498d4e8",
"sha256:66c61f837b3e5c897bd2a90149afd615f59d24c72c893526485bca1b40f6ec49", "sha256:4a125855110bedee3011929e1d050c20d74fa00a36d1ec602be677847b89d764",
"sha256:6ba33ff1d1275586bb4d83687c59783dad60b66ef3d420c04982bae7e0d75f9b", "sha256:4e734f8a5cf002316cc81b80d8a91a0f7c62d631270abd913746644fb9ae288d",
"sha256:6c835b0b38d795dde7aaa4581626490ca5fcfbd4eefe9572ac18d9eb2427d215", "sha256:4efed5de773df44042a07a50ea8dc476a4c120bfd3fcc4fd7a7ea145196832b2",
"sha256:6cd51dd02943b703e10eb536722c5fd205b6084333dac5b9c114bdbbc2c46b3a", "sha256:50d224b482e1e18fa6bbe90d05125993122c5530b0b83f48829d7a535e2b60f2",
"sha256:6d15672b32f0891940691bac16a854af164e694f0b9d21bebfddd13e3c7d2f03", "sha256:521f871864880cabe361060f070516a56a54abc3e96f07bee9ba8b061eada891",
"sha256:6dc37f78187655cf95032bee0e9578ff89d39734def8e27a6bf930d4caa08042", "sha256:53b1df29ffe966cde1d2f0085b6acfcd237504627d406a51717ef3849ec88831",
"sha256:6df0c5f2a879ea47ec2f88f4abfb0ca14c2af174eda923b7f65e9954a4aecf38", "sha256:553f6c0caa98f314d97c671c8924fb97cd59515258916283cea315bc099c4200",
"sha256:73db6c7374aebb94e2758e1c34c0090b1dee39f13a28b812387c8e9478cdbee1", "sha256:5909e2273f8b6fcea93c95564aa0f366ff9261a544a7a5d640ea95341321cc37",
"sha256:740e4e489759b749aaed695e8430d28a039c11765fc5e4d1b20bfad9c7e192f1", "sha256:5917a20e0a7b763a8eb2786422d2a534fa0e5645baf12376045a64b63a711cb1",
"sha256:7a1388738fcce0ddc8e742d2d1c0619911299f339d54a19496bcbecfb4d7e775", "sha256:5d61bc0a62b4eee11039bf29d4bdbb26efcff760dfb9d8e0739740028aa52b0f",
"sha256:7a78e0c94d242aa054f97e503fb05485df63b3d8e66ff5ec8710fc0dcd1fb83b", "sha256:5f9a82f90a21660fd0313a81c838bff89a13c7921c317abfc3117e49f9d46c84",
"sha256:7c19511733a8ccf998042b64ac2077c334d73f2d0df4ce80b158694191a1f707", "sha256:62aee4bd128e17871980e4847cc4b94b67651de612bc96dd3d7ebf647c68a6e4",
"sha256:842f27673350dc22659cc0dfba035bf610927810fcfb6a9ddea594dcb3cfe774", "sha256:641f65f5414b8990251bd7609513a696831558f69d2ca77d65dc3f7087f31267",
"sha256:84c32c68792170bbb19bc94ec5c5d8823ba31d177709d686c63cd6a9e8ef5cd3", "sha256:6d84d87f6c1b2131273b8078f5863d980269fa53139d7f7fa76e6099e2a00bd1",
"sha256:84e4ef15d432f914394828f5127482584bd8bb6ca9d95220b25bc32a5bdec501", "sha256:6eaa9919f7faf162d2acf66e1632c4588840589eb0030688907c9eb6a5ecae17",
"sha256:85cf4f09f7159c29967212af685d2819f960d9136d931420fef107683d121f56", "sha256:6f8d364d53cc0854d910f2305726a8254acb527f13fa933dc213a591e21e7ffa",
"sha256:86d1bd875161ce4d5303e667ad19fb7436476d1610aa04b21c14838c1669f32a", "sha256:6f8dfd56b10c4d66f1c2338b4caeeec5c0d2cda0243e66e02aca68bb02f7ea78",
"sha256:89c46416ccf0f457bfd4df67670c79052116f07ffb3951c5103d178c6bf372ec", "sha256:6fefc5b57d9a345d90e283a7547661b3c5921480c14d039077d3181a7b6226de",
"sha256:8afe44228388f9282b4e3804e0212fc7f000ede156e73b2068f61fb821598c9f", "sha256:70b5bd5cbfd806ceb6f57bb9bc287a073b1cb51029b25197eb9acd45cb7f1db4",
"sha256:8bf2a83fcbcd3dd53b80574655a54459e7ddd591d936ac67e636330764c75907", "sha256:72122b850d58c4ae0612c9b9bbabeddbb092b503eb39d87249da323ba1b074a8",
"sha256:8d4c26ef61db31c6f33a572b40c6eff312131cac83300bbf6d75fbed1e5f073e", "sha256:7479e41d20278484aecee14ed2a52e83cc36f3033f176fc2d1c7b078628e8bc9",
"sha256:8e9f37f6497f8dbb1c1e254c77224ad06cfde22c1337230d308aeaab043eea27", "sha256:74cb2237406296f92a31ea762ad0daffcfb2be39e567e62595880948eb9e9e84",
"sha256:92ff21001d59d47f929418d0dae55a97be16221c13e1f7ed134bdc79189475fb", "sha256:7586a835ed5e213593e35e0d6f90197dd76412fdcba62e05b15df72806af1e2b",
"sha256:963d7c46d8fc824eb5957086702e65ca552de4595a95c5c7906b41162e6459cc", "sha256:75d0b2bffb2e260a0f3578a11a4999a713c94d1bd8de7cfe692c840e20ae83cf",
"sha256:97da940c5bc7f9ca1ddde294fac46f75ca4be2a7b7be5a32e87b6195f2f4203d", "sha256:797e8846a4c7a18a9b3abdd437ca2fa06d39223df7a6fdcae57adeb7cc3d7a95",
"sha256:985a9eb136e7897bcedba873cf30b51c19481d94ab31a391d05eeecf27c390ba", "sha256:7b7e2028a565bb04cdf73a91634722e3de40e1d8fed1adf8aa1ba8952f48ef07",
"sha256:9c39968cf5547d68f97a893c518f02f6caca94942206a958d8aa9325f8c3e330", "sha256:84d42f63b1e7368194704159637e534280540369b35758a4daa712bf277e80ef",
"sha256:a27e7e1ead8fb200a6d909b23031e3adf0dc2be0b2715fae61ca0af6b4a77de8", "sha256:85d3d338284fbfbe173243c3cc62e510c6fa0d6d023e67da2292bd7578c734e3",
"sha256:a3a66bd7612ab626a592d5c0d6b072bd48c0c1f6ab3ed1d1dbb427dbe7472ed2", "sha256:882b13542d7bd20f79cb92fc31ecc9587037278d0a6b36c14b734f9ac2cb8890",
"sha256:a433f014c207ffc4b3eda0165fbd4d7d978b53cbdd6e71d441531221b2b1b879", "sha256:89fd1e706f1870ea4a8a91c6b2434123e6d76d6ea1fac9bf7904cf71fca8b9cf",
"sha256:a508df37d162ad523edd05477721e981ca33607ebbcd398eb000b0e7e9dca855", "sha256:95d72124353a530ffa5a65f1f94a4396521f5472f0fde79b93dd66a3addaadff",
"sha256:a970e377224e4f2e703e4ed72135a16c1539feb0d7f57f9e1dfa4514aa6fb257", "sha256:96cff73359be465a4a70a2f15b72c384055a6be16c670f983633a9dc93cdb2e2",
"sha256:aafd357af8d0de5267d3bc88e2384da30f05c38446a61425ae565925bc2ca9ba", "sha256:99aedd20daacb32f377152c9103d8d0271f32d1932bd39a5ed2cd2eef97f7e07",
"sha256:af8d4f64794823fcdaa1ab4d01e40361e0dc0ddda9a6523e96a72b47a9e96e7f", "sha256:9e4d342cd71db3c8c3be74acfe26b38503f2f5948c902072319405c5b5bc5313",
"sha256:b0008658e6308f71a3aabfbf1051cc71993fb9a993ccfa0cf711b52a1bc029dd", "sha256:a0772ad66f346038fe05cb2928866ff1b21bcaa9ec3f14709fa1d419ed1dc287",
"sha256:b0ad821964a7701e2b80c6f8b424b6d4ca575fefb1aa04227967ef78fa15fcd5", "sha256:a08ffa490443767a1783b372d39a9156da37a93a6c490e03a439aacf315f8a79",
"sha256:bf289d6fca3346ef133334bde88c08d4f1b76c9f3ef53cbc6be1e96bae3e3305", "sha256:a1ef1d6c90389c366ade34bc6b100e823569c60bbb0b0f2cc3b308031090b252",
"sha256:c0693e9efcb492f48b61453b6fca3cee60c544c494fa1eb7ab63dbe493189db4", "sha256:a5146468a76bbe8f4035f23a78813c5c433c70c0ca44eb0ba5558627a9e644b8",
"sha256:c3c95d6c44d9d2d53bee5f5bbffdb2a1e6174c8c47803ac6ad7465e8d9e6e2d7", "sha256:a5d2ceb2e9d42ac236f0da7b2f9e8237818d32a10d892b06f30f7160ee4365ae",
"sha256:c4bc66dcfe87ef776aea114e45db658895e4c812bb044ad3a4d52abcb5d4083c", "sha256:a8bfbc5f77e95f485bf046d4a19bb773866cdc9d1b21c27a194366a55d7fe361",
"sha256:c5d4d20b96d643fd866d8d49b2fec2826eea99e7852c5aa0326d14e8ca517769", "sha256:a915e77adc126bd79867b7cfecc930021ef1a2599475dda058ae80537a7068ec",
"sha256:c7834d1000ac856234e7b574ed2ccf2136aab325d84051edb1db06c17e295df4", "sha256:b1d8313b13acfdef19c5ff793fdf397bae3d8d75181f6eee62604f13e4ec20a8",
"sha256:ca9473848bbf422b1c91c907bed9db66d7c29f37a6406c4614bd3fa782d0e2ab", "sha256:b41867d5decd7cd62e12cdacfc45c5d8f6eae872578ae01d78900174d5e47b82",
"sha256:cd19d6e0f8b82dd92e9e9836baf8c5d3a18d15d06c7838c64dae0f45b0cad24d", "sha256:b4b6aeaa12ff46df7478150e063f540fa976c41203739e425bfb823d479d7209",
"sha256:cd4187891ebc44e782c5606393e16818d63bc1dbd3a0028bafed62e2d0fdd3f2", "sha256:b4eae2d5bc1a91033450fd4381c04f33db7d4c9cfd31046c4708c8c1323c06d0",
"sha256:cdb4bc4cb82e66a41d4f4ec9fb80f7ed7981cf7786efb6a94cf47ea27ec90e28", "sha256:b572daaafbd867bb5c5f324c918704ddd6d76af1cc7c2be483c3649b76ce7940",
"sha256:cf17baca8873260f6e80861feb8048c898b8a90569c374f430370240bd078995", "sha256:ba5e545b3209e8aa5b6af88e7032814473e57d60d32d3fc6b6185453733a4b26",
"sha256:cf85910f5d8506467e9a6fc9be3140f4ffe49e2baa973b71c83822c6e6e88480", "sha256:ba74adbc182ee8d4781856ec3cd1ed61fa16839f6a6b2bc708e70b281211938b",
"sha256:d8115befc7092c4b5d4b32093d38bf4c8a543b84d9a7f7f632055854bd89cb63", "sha256:bc238641d3bc35dc79965f330c7f0f16ca992cf999c8892dce0bd36c32056eee",
"sha256:d8d971f7e6c13c7e71b566683cdf8fa9569dfdca1443ee2545b3b8c68f3b6338", "sha256:bde7e7ff0f17e87aca9ef23f66b80540a2de0ff8e2c26af55eb2e288a2a5f74f",
"sha256:da8fbddf3e00a9e8e18afda67721e71cc69f1a81ba16a4a7b50f57efa47d2991", "sha256:bdeb48657db508e8bc299744aa431798efdf090feb3959cf0123167c9251ebb0",
"sha256:daadac34cefe67ea03a7d2324e03fc9b37ec8820604f1563e7d424471bee29b6", "sha256:c32befa8f915f3a4510cd097cd7874b9d8782accb06562d8aecd5b40e879e980",
"sha256:dbd90d3b9bba566c36b6613d9e867e69754058a1b8608d9b7c973fd3cd97ef69", "sha256:c697b250a935030a128b45b41f507a4d33a082d8b8e12311c7e73fbb3970f057",
"sha256:dbe27e880218afc123c464359553771cedab793130eb3b0c72bd3f678512a2da", "sha256:cc31fbfd9ac25d46603c4d27c4ee94593202d55a437f0c1e83a17570f596e21e",
"sha256:dbf08eead0483ecaf275c2f447b704d1583278f7abd6f0e945fccd6a581c7df4", "sha256:cf3dc6f7c14340241260bf63e5d6006b2ee7db45dafcb39c16fdf164ea0240a0",
"sha256:dd0ac28b9c0e20c3b5e6840f6651a38303718f20c12df104c8e544ad245b2c24", "sha256:cfec229e33d3772ee71d81bee9145f195f58cde65126f54820026a41c0da1ab8",
"sha256:dfb99fe1bd951d2da7d5dd90325c8a3c3834dd614339f536a45cbd1bc1335f1e", "sha256:d0bdb220d7fa3b6deb5a108cd5c37109e4bec12b7aa9aa56f2d8f9c55f1f113e",
"sha256:dfbb07be66cb96a289c876aaab7ac46da4fb70f6526298f1fda60076b971d5f0", "sha256:d3cf203de31371289d4c1e6b4d30c9f6de95b2bd2b300fe5468ff946299d0e48",
"sha256:e20f3bcf50192caea969b4bb674c8f6dc607fb5f8abe6b76248f698e9e4cab84", "sha256:d5c4d4ef923464dc5b39d39b1a41209a23e387698a254e81813d0757f76ff00a",
"sha256:e28dabffcbd5525bf5f36d482764e3e56b513bce06a75b2fb4b540bedad80348", "sha256:d8313cfecb3b15d1c1a7e5c70c0e2d42bbc9fe0d616a18cc25dc91d63290139c",
"sha256:e5616ffeb5b173b540e2db230546a476c5618cf25dac5bb9149c06fc6b0a9e4f", "sha256:da030729eb8ef386569e78c10e2429adb10026ce82989fdeb906b037314d66c7",
"sha256:e5c64aa5f61d986a4f1b4cc319056dcb7198c3c25e3a81b3302a396479e5561a", "sha256:e09fa8ede2105af24955c620675d5d778b26c51086379ef7ee98e1208c2341e4",
"sha256:e6998c4e1bd862d58426ab654b99cf1f52163acff767714048711225aaf6fc3f", "sha256:f3768fa39d0c5a2578b285e49e8d42230bb182bb2f7984840549f89c04ce4a56",
"sha256:e6c5421e4eb59f9f15822b9002b26a78a8f9d4e507e4f79d6f3d5f992db4be0a", "sha256:f48eeba6c0bb91321dbefc60527d945f20ccee3f0066bb3ba0d9b71120ec9417",
"sha256:ebe5ec3b51704119ca66717828631a777bc64132517f445d0b9ac2f30dd38264", "sha256:f558408add7be748978c52796ea852dde5d348a00f8ba7518db848d32154f022",
"sha256:f035aa4cdf3193bc03e7e36b4154d9036f87d002ba553839ec73412242de62ef", "sha256:f681e197bf6552df3bb7a3abfd676e81316b69e36e7263e72383477174032ca2",
"sha256:f26cdbf79bd0792bc65b7825b356040c56c365041a6ae7c44e5655f8fa173fe6", "sha256:f6e95bfee4a72a7eb6fb4ca057ac5da297df68d302c63c300a5f400a0003fe31",
"sha256:f48bb00711eefaefbfafd791da8bd8796d683aef6a4c320b7a393555f6d23115", "sha256:f810dd02b4a9647eacbe4eab617111c0e3ffc68e923e3ff172948db601d2ba1e",
"sha256:f639bbe255623af299f75b2ef8e98b0c88ead8b9f420d20abe487fb8a33238b6", "sha256:f8c78cffb3a35c4410513c3eb7989de36028c84277c04f07c97909dd94c23a75",
"sha256:f8e208e3bc3909d82c7ecb936bad35cc2271eb425e7faac352618c26a23568d0", "sha256:fb8e37ecf37382c02af83da521df5a77561441bc4cbb93b00627e015b7bbf349",
"sha256:fa18a2886a229a0d53a2c6c3d109079cdd2550466f2ae2286e43a1c66d47d627", "sha256:fbd4e45d9207aed97257157f0ef268757f3687af95d7047a9e290a559f3729ea",
"sha256:fc22823c633e95c6b5298f9ffe2d77f0f1787f2d03c47ccb7dff006e6c30fac3", "sha256:fd7f6c7e63717cc5f69bf814b61d4c5725c1a8976b03567c87db6a048d7e16df",
"sha256:fc2bdcc2fecb3e3382bbf2834d81b981c3b8978be67c54c2aeeba01dee911161" "sha256:feb3a70be5b9af031596b8328532997e0019d91e11db1cd607087ed32ce59727"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==5.0.11" "version": "==5.0.13"
}, },
"lxml": { "lxml": {
"hashes": [ "hashes": [
"sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2", "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2",
"sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773", "sha256:07a4a68e286ee7a1ed7dfb8af83e615757c0ccfe9f18c6b4ea6771388d9ba8c9",
"sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7", "sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60",
"sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad", "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c",
"sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635", "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7",
"sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286", "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a",
"sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9", "sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83",
"sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54", "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072",
"sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c", "sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8",
"sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618", "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462",
"sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7", "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0",
"sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39", "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085",
"sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69", "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f",
"sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551", "sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30",
"sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc", "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1",
"sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd", "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77",
"sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd", "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740",
"sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405", "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b",
"sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289", "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c",
"sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b", "sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621",
"sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a", "sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e",
"sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d", "sha256:32ab449a5486f6c758e849bb86710d0e45edc24a04e250c01555f8f5653958f8",
"sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd", "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca",
"sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac", "sha256:34c2d737beabfe35baada43941ed519251e9a12e779031496bcd5d539fcfd730",
"sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245",
"sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad", "sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1",
"sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f", "sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004",
"sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad", "sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d",
"sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c", "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52",
"sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292", "sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5",
"sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544", "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf",
"sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc",
"sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120", "sha256:441dd227fa0690eb9fc81edabc63cdcefc212bba99b906dcf6e32cc1a9d3e533",
"sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512", "sha256:469e3618338bd7ab5beb412d2439825479fcf0dab99e394ca563dbc4eaf6c834",
"sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb", "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947",
"sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32", "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a",
"sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", "sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2",
"sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec", "sha256:53c909b62a0532183542fed00c5a7218258c56292d409bc789886fe1cb04c438",
"sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc",
"sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43", "sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea",
"sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037", "sha256:55b03549819867ea141c0202242c4816c82e52ec36e7e648db9d8da5a3dc3ed6",
"sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13", "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e",
"sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03", "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c",
"sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64", "sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383",
"sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485", "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955",
"sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", "sha256:5bec7d03d78d853597d6107854c2310ce3f761fd218fe9fe91d5101fcf6c2efe",
"sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb", "sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074",
"sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", "sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c",
"sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8", "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a",
"sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39", "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb",
"sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842", "sha256:639f6c857d91d9be29bd7502348d6736dab168b54b5158cd899abf11684dc186",
"sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f", "sha256:640f97d43d867bcb9c75b3af013b64850756b746cb6bce8ace83b70da3abba9d",
"sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105", "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1",
"sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c", "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f",
"sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7", "sha256:6689e828a94eee4f139408c337bb198e014724bb8a8c26d3cfac49d119ed69a6",
"sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6", "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736",
"sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5", "sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6",
"sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d", "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2",
"sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9", "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b",
"sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d", "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7",
"sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb", "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14",
"sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f", "sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009",
"sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755", "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca",
"sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb", "sha256:76447f65250ed2501ead1a1552f5ce8edff159a86f308348e6a9c4acb5e1f1b4",
"sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280", "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635",
"sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace", "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee",
"sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e",
"sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9",
"sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5", "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603",
"sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2", "sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08",
"sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3", "sha256:83b6b30eb131da7a75b601f28c5d6971e6ed3e887919bf6b6a1ad3c2df289080",
"sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585", "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525",
"sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce", "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5",
"sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946", "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f",
"sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", "sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067",
"sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a", "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e",
"sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7", "sha256:8be8ad51249698103d24b0571df35a10990fbe93dd043b6c024172189485f5e3",
"sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5", "sha256:8d43ca737b20e106e4aebc42b2f3ae19f00ba63d7eb731698ee083d72d15646f",
"sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28", "sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485",
"sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4", "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13",
"sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c", "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383",
"sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50", "sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315",
"sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9", "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e",
"sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c",
"sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16", "sha256:9f76acfb5f68ba982635a53fd985a8044be98a35b43232c2a1ee235ffab3e1dd",
"sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099",
"sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919", "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660",
"sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4", "sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510",
"sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a",
"sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec", "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b",
"sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd", "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5",
"sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8", "sha256:aae97dfdb60715c164419ac2532a76d013c3918a665eb6cb7288098b5f349aaf",
"sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f", "sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28",
"sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940", "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00",
"sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72", "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef",
"sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366", "sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1",
"sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814", "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955",
"sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690", "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590",
"sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137",
"sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a", "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf",
"sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819", "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40",
"sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c", "sha256:bdebcc8a75d38c7598dfb2c9ed852d7a9eb4a10d6e2d0764b919b802bf32ac88",
"sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86", "sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e",
"sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317", "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840",
"sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180", "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2",
"sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383", "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca",
"sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee", "sha256:c674693f055fa2495de12292cb45e9944199d8eaef5a2dec45175c7c61cb73e3",
"sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465",
"sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc",
"sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9", "sha256:c9a4b821dc7055bf9e05ff5719e18ec501f75c0f0bbfabd573b277559780833d",
"sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e", "sha256:c9f79d5325907f13e1be0b3e4dacc1049d1dffc4aeee3c995284bea5fe0fab7d",
"sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd", "sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa",
"sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3", "sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a",
"sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d", "sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a",
"sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad", "sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206",
"sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea", "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e",
"sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785",
"sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d", "sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8",
"sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de", "sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a",
"sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1", "sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b",
"sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", "sha256:e07c65f443c887bbcf31cc1771d932ecc192a5273943589b3c7572b749f1ffb2",
"sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11", "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6",
"sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9", "sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6",
"sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354",
"sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776", "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818",
"sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f", "sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84",
"sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93", "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909",
"sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a", "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038",
"sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5", "sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d",
"sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d", "sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2",
"sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", "sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf",
"sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3", "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc",
"sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086", "sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d",
"sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215" "sha256:ffecec8eb889b58ba9be5b95fb1cc78e22ea8eedea38e8736a1568fe1979250e"
], ],
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==6.1.0" "version": "==6.1.1"
}, },
"niquests": { "niquests": {
"hashes": [ "hashes": [
@@ -466,9 +466,18 @@
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.9.0.post0" "version": "==2.9.0.post0"
}, },
"python-dotenv": {
"hashes": [
"sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a",
"sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"
],
"index": "pypi",
"markers": "python_version >= '3.10'",
"version": "==1.2.2"
},
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
"sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c",
@@ -667,7 +676,7 @@
"sha256:fb5662abc48582c9eac388e43b1e58b9865458d20e3eb667292afd10e9b3e244", "sha256:fb5662abc48582c9eac388e43b1e58b9865458d20e3eb667292afd10e9b3e244",
"sha256:fbe895164d31be3c0ab5c3cfdfe13054723d72440d8144239bbd4c8a5be088d0" "sha256:fbe895164d31be3c0ab5c3cfdfe13054723d72440d8144239bbd4c8a5be088d0"
], ],
"markers": "(platform_python_implementation != 'CPython' or python_full_version > '3.7.10') and (platform_system == 'Darwin' or platform_system == 'Windows' or platform_system == 'Linux') and (platform_machine == 'x86_64' or platform_machine == 's390x' or platform_machine == 'armv7l' or platform_machine == 'ppc64le' or platform_machine == 'ppc64' or platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'arm64' or platform_machine == 'ARM64' or platform_machine == 'x86' or platform_machine == 'i686' or platform_machine == 'riscv64' or platform_machine == 'riscv64gc') and (platform_python_implementation == 'CPython' or (platform_python_implementation == 'PyPy' and python_version < '3.12'))", "markers": "python_version < '3.12' and (platform_python_implementation != 'CPython' or python_full_version > '3.7.10') and (platform_system == 'Darwin' or platform_system == 'Windows' or platform_system == 'Linux') and (platform_machine == 'x86_64' or platform_machine == 's390x' or platform_machine == 'armv7l' or platform_machine == 'ppc64le' or platform_machine == 'ppc64' or platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'arm64' or platform_machine == 'ARM64' or platform_machine == 'x86' or platform_machine == 'i686' or platform_machine == 'riscv64' or platform_machine == 'riscv64gc') and (platform_python_implementation == 'CPython' or platform_python_implementation == 'PyPy')",
"version": "==1.8.1" "version": "==1.8.1"
}, },
"recurring-ical-events": { "recurring-ical-events": {
@@ -683,7 +692,7 @@
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.17.0" "version": "==1.17.0"
}, },
"tzdata": { "tzdata": {
@@ -696,11 +705,11 @@
}, },
"urllib3-future": { "urllib3-future": {
"hashes": [ "hashes": [
"sha256:7a9dc11783c97b5013d3271b07c26f946f3f51d4ea7dfd1742e267a245474cce", "sha256:18673623d88ec8f54f7a9648a8c7075c98c07f78bf077a9a7d53fd0cf9f8ede7",
"sha256:7c4e783310872869fd99486c8d42ed82eb5bbf9541dea6826b1d531caf73190c" "sha256:370e83b864a67013d07fe69510a51120122de32feca02847205d4c44efc559c1"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.20.903" "version": "==2.21.900"
}, },
"wassima": { "wassima": {
"hashes": [ "hashes": [
+153 -108
View File
@@ -1,131 +1,144 @@
# README: ICS-Importer für mailbox.org unter Linux # ICS-Importer für mailbox.org unter Linux
Dieses Projekt durchsucht ein mailbox.org-Postfach per IMAP nach `.ics`-Anhängen und importiert enthaltene Termine anschließend per CalDAV in einen mailbox.org-Kalender. mailbox.org dokumentiert Thunderbird/IMAP für E-Mail und CalDAV für Kalender; die CalDAV-URL des Zielkalenders wird in mailbox.org im Kalender über **Eigenschaften** angezeigt. [kb.mailbox](https://kb.mailbox.org/de/privat/e-mail/e-mail-einrichtung-mit-mozilla-thunderbird/) Dieses Projekt durchsucht ein mailbox.org-Postfach per IMAP nach E-Mails mit `.ics`-Anhängen und importiert enthaltene Termine automatisch per CalDAV in einen mailbox.org-Kalender.[cite:55][cite:45]
## Überblick
Der technische Ablauf ist bewusst einfach gehalten:
1. Das Python-Skript verbindet sich per IMAP mit mailbox.org und durchsucht einen Ordner, standardmäßig `INBOX`.[cite:56][cite:55]
2. Es erkennt `.ics`-Anhänge, berechnet einen Hash als Duplikat-Schutz und verarbeitet nur neue Anhänge.
3. Die Termine werden per CalDAV in den gewünschten mailbox.org-Kalender geschrieben, dessen URL in mailbox.org über die Kalendereigenschaften ermittelt wird.[cite:45][cite:51]
4. Die Ausführung erfolgt manuell oder stündlich per Cron.
## Voraussetzungen ## Voraussetzungen
Benötigt werden ein Linux-System, Python 3, `pipenv`, ein mailbox.org-Konto sowie Zugangsdaten für IMAP und CalDAV. Wenn bei mailbox.org die Zwei-Faktor-Authentifizierung aktiv ist, sollen für externe Anwendungen App-Passwörter beziehungsweise Applikationspasswörter verwendet werden. [kb.mailbox](https://kb.mailbox.org/de/business/adressbuch-und-kalender/caldav-bei-thunderbird/) Benötigt werden:
## Projektinhalt - Linux
- Python 3
- `pipenv`
- Ein mailbox.org-Konto
- Zugriff auf IMAP und CalDAV
- Bei aktiver Zwei-Faktor-Authentifizierung ein App- bzw. Applikationspasswort für externe Anwendungen.[cite:63][cite:45]
Die typische Struktur des Projekts sieht so aus: ## Projektstruktur
```text ```text
ics-importer/ ics-importer/
├── ics_mail_importer.py ├── ics_mail_importer_env.py
├── config.ini.example ├── .env.example
├── config.ini ├── .env
├── imported_uids.txt ├── imported_uids.txt
├── ics_importer.log ├── ics_importer.log
── cron.log ── cron.log
└── README.md
``` ```
`ics_mail_importer.py` ist das Hauptskript, `config.ini` enthält die Zugangsdaten, `imported_uids.txt` dient als Duplikat-Schutz, und `cron.log` kann die Ausgabe des Cron-Jobs aufnehmen. Der Duplikat-Schutz ist sinnvoll, weil bei wiederkehrender IMAP-Prüfung sonst identische ICS-Anhänge mehrfach verarbeitet würden. [github](https://github.com/Vilhjalmr26/import_ics) ## Installation
## Installation mit pipenv Projektverzeichnis anlegen und Abhängigkeiten installieren:
In das Projektverzeichnis wechseln und die Python-Abhängigkeiten installieren: ```bash
mkdir -p ~/ics-importer
cd ~/ics-importer
pipenv install python-dotenv caldav icalendar
```
`python-dotenv` liest Schlüssel-Wert-Paare aus einer `.env`-Datei und stellt sie als Umgebungsvariablen bereit.[cite:162][cite:164]
## Konfiguration mit `.env`
Eine `.env.example` kann als Vorlage verwendet werden:
```dotenv
IMAP_HOST=imap.mailbox.org
IMAP_PORT=993
IMAP_USERNAME=ihr-name@mailbox.org
IMAP_PASSWORD=IHR_PASSWORT_ODER_APP_PASSWORT
IMAP_FOLDER=INBOX
IMAP_UNSEEN_ONLY=true
IMAP_MARK_AS_READ=false
CALDAV_URL=https://dav.mailbox.org/caldav/IHR_KALENDER_ID
CALDAV_USERNAME=ihr-name@mailbox.org
CALDAV_PASSWORD=IHR_PASSWORT_ODER_APP_PASSWORT
```
Die IMAP-Standardwerte für mailbox.org sind `imap.mailbox.org`, Port `993`, SSL/TLS und die vollständige E-Mail-Adresse als Benutzername.[cite:56][cite:55]
Die vollständige CalDAV-URL des Zielkalenders wird in mailbox.org im Kalender über **Eigenschaften** angezeigt; für Thunderbird und andere Clients wird `https://dav.mailbox.org/caldav/XXX` verwendet, wobei `XXX` die individuelle Kalender-ID ist.[cite:45][cite:51]
`.env` lokal anlegen und schützen:
```bash
cp .env.example .env
chmod 600 .env
nano .env
```
## Bedeutung der Variablen
| Variable | Bedeutung |
| --- | --- |
| `IMAP_HOST` | mailbox.org IMAP-Server, normalerweise `imap.mailbox.org`.[cite:56] |
| `IMAP_PORT` | IMAP-SSL-Port, normalerweise `993`.[cite:56] |
| `IMAP_USERNAME` | mailbox.org-E-Mail-Adresse.[cite:55] |
| `IMAP_PASSWORD` | Passwort oder E-Mail-App-Passwort bei aktiver 2FA.[cite:63] |
| `IMAP_FOLDER` | Zu durchsuchender Ordner, meist `INBOX`. |
| `IMAP_UNSEEN_ONLY` | Wenn `true`, werden nur ungelesene Mails geprüft. |
| `IMAP_MARK_AS_READ` | Wenn `true`, werden verarbeitete Mails als gelesen markiert. |
| `CALDAV_URL` | Vollständige CalDAV-URL des Zielkalenders.[cite:45] |
| `CALDAV_USERNAME` | mailbox.org-E-Mail-Adresse als CalDAV-Benutzername.[cite:45] |
| `CALDAV_PASSWORD` | Passwort oder Applikationspasswort bei aktiver 2FA.[cite:63][cite:45] |
## Python-Skript
Das Skript `ics_mail_importer_env.py` nutzt `python-dotenv`, `imaplib`, `email`, `icalendar` und `caldav`. `python-dotenv` ist speziell dafür gedacht, Werte aus einer `.env`-Datei zu laden und als Umgebungsvariablen verfügbar zu machen.[cite:162][cite:164]
Beispielhafter Programmstart:
```bash ```bash
cd ~/ics-importer cd ~/ics-importer
pipenv install caldav icalendar pipenv run python3 ics_mail_importer_env.py
``` ```
`caldav` wird für den Zugriff auf den CalDAV-Kalender benötigt, während `icalendar` ICS-Dateien parst; für das Mail-Lesen werden Standardbibliotheken wie `imaplib` und `email` verwendet. [github](https://github.com/python-caldav/caldav) Das Skript erzeugt oder nutzt dabei unter anderem diese Dateien:
Den Interpreter-Pfad des Pipenv-Umfelds kann man mit folgendem Befehl prüfen: - `ics_importer.log` für die Programmausgabe
- `imported_uids.txt` für den Duplikat-Schutz
- optional `cron.log`, wenn die Cron-Ausgabe dorthin umgeleitet wird
## Erster Testlauf
Vor dem Cron-Einsatz sollte das Skript immer einmal manuell gestartet werden:
```bash
pipenv run python3 ics_mail_importer_env.py
```
Wenn die Zugangsdaten korrekt sind, verbindet sich das Skript mit IMAP, liest passende Anhänge und importiert neue Termine in den angegebenen CalDAV-Kalender.[cite:55][cite:45]
## Cron-Einrichtung
Den Python-Pfad des Pipenv-Umfelds ermitteln:
```bash ```bash
cd ~/ics-importer cd ~/ics-importer
pipenv --py pipenv --py
``` ```
Pipenv dokumentiert virtuelle Umgebungen und deren Interpreter-Pfade explizit; dieser Pfad ist später für Cron praktisch. [pipenv.pypa](https://pipenv.pypa.io/en/latest/virtualenv.html) Stündlicher Cron-Eintrag:
## Konfiguration
Die Vorlage kopieren und bearbeiten:
```bash
cp config.ini.example config.ini
nano config.ini
```
Beispielinhalt:
```ini
[imap]
host = imap.mailbox.org
port = 993
username = ihr-name@mailbox.org
password = IHR_PASSWORT_ODER_APP_PASSWORT
folder = INBOX
unseen_only = true
mark_as_read = false
[caldav]
url = https://dav.mailbox.org/caldav/IHR_KALENDER_ID
username = ihr-name@mailbox.org
password = IHR_PASSWORT_ODER_APP_PASSWORT
```
Die IMAP-Einstellungen orientieren sich an mailbox.org für Thunderbird, und die CalDAV-URL des gewünschten Kalenders wird laut mailbox.org im Kalenderbereich über die Eigenschaften des Kalenders ermittelt. [kb.mailbox](https://kb.mailbox.org/de/privat/e-mail/e-mail-einrichtung-mit-mozilla-thunderbird/)
### Bedeutung der wichtigsten Optionen
| Schlüssel | Bedeutung |
|---|---|
| `imap.host` | IMAP-Server von mailbox.org: `imap.mailbox.org`. [kb.mailbox](https://kb.mailbox.org/de/privat/e-mail/e-mail-einrichtung-mit-mozilla-thunderbird/) |
| `imap.port` | Standardport für IMAP über SSL: `993`. [kb.mailbox](https://kb.mailbox.org/de/privat/e-mail/e-mail-einrichtung-mit-mozilla-thunderbird/) |
| `imap.folder` | Zu prüfender Ordner, meist `INBOX`. |
| `imap.unseen_only` | Wenn `true`, werden nur ungelesene Nachrichten gesucht; das reduziert unnötige Prüfungen. |
| `imap.mark_as_read` | Wenn `true`, markiert das Skript verarbeitete Nachrichten als gelesen. |
| `caldav.url` | Vollständige CalDAV-URL des Zielkalenders aus mailbox.org. [kb.mailbox](https://kb.mailbox.org/de/business/adressbuch-und-kalender/caldav-bei-thunderbird/) |
| `caldav.username` | Meist die mailbox.org-E-Mail-Adresse. [kb.mailbox](https://kb.mailbox.org/de/business/adressbuch-und-kalender/caldav-bei-thunderbird/) |
| `caldav.password` | Passwort oder App-/Applikationspasswort bei aktiver 2FA. [kb.mailbox](https://kb.mailbox.org/de/business/adressbuch-und-kalender/caldav-bei-thunderbird/) |
## Erster Testlauf
Das Skript kann manuell getestet werden mit:
```bash
cd ~/ics-importer
pipenv run python3 ics_mail_importer.py
```
Dabei werden neue `.ics`-Anhänge gesucht, importiert und im Log protokolliert. Python-Lösungen für IMAP-Anhangsextraktion und ICS-zu-CalDAV-Import folgen genau diesem Muster aus Mail-Abruf, Parsing und Import. [stackoverflow](https://stackoverflow.com/questions/6225763/downloading-multiple-attachments-using-imaplib)
## Stündliche Ausführung mit Cron
Die eigene User-Crontab wird mit `crontab -e` bearbeitet; User-Crontabs liegen auf Debian-/Raspberry-Pi-ähnlichen Systemen typischerweise unter `/var/spool/cron/crontabs/`, sollen aber nicht direkt bearbeitet werden. [cronitor](https://cronitor.io/guides/five-places-for-cron-jobs)
Für eine Ausführung **stündlich zur vollen Stunde** sieht der Eintrag so aus:
```cron ```cron
0 * * * * /home/hans/.local/share/virtualenvs/ics-importer-wOz4rK-o/bin/python /home/hans/ics-importer/ics_mail_importer.py >> /home/hans/ics-importer/cron.log 2>&1 0 * * * * /home/hans/.local/share/virtualenvs/ics-importer-wOz4rK-o/bin/python /home/hans/ics-importer/ics_mail_importer_env.py >> /home/hans/ics-importer/cron.log 2>&1
``` ```
Alternativ ist auch `@hourly` möglich; beide Varianten entsprechen einer stündlichen Ausführung, wobei die klassische Cron-Syntax mit `0 * * * *` die Ausführung zur Minute 0 jeder Stunde beschreibt. [wiki.ubuntuusers](https://wiki.ubuntuusers.de/Cron/) Die User-Crontab wird mit `crontab -e` gepflegt; die direkte Bearbeitung der Crontab-Dateien ist nicht empfehlenswert. Für stündliche Jobs sind sowohl `0 * * * *` als auch `@hourly` übliche Varianten.[cite:321][cite:55]
### Cron-Eintrag ohne eigenes Umleitungslog ## Logrotation
Wenn die zusätzliche Datei `cron.log` nicht gewünscht ist, kann die Umleitung weggelassen werden: Wenn `cron.log` mitgeschrieben wird, sollte die Datei per `logrotate` rotiert werden. Eine typische Konfiguration unter `/etc/logrotate.d/ics-importer` sieht so aus:
```cron
0 * * * * /home/hans/.local/share/virtualenvs/ics-importer-wOz4rK-o/bin/python /home/hans/ics-importer/ics_mail_importer.py
```
## Logrotation für `cron.log`
Für benutzerdefinierte Logs ist `logrotate` der übliche Weg unter Linux. Eine eigene Datei unter `/etc/logrotate.d/` ist dafür die gängige Methode. [dash0](https://www.dash0.com/guides/log-rotation-linux-logrotate)
Beispiel:
```bash
sudo nano /etc/logrotate.d/ics-importer
```
Inhalt:
```conf ```conf
/home/hans/ics-importer/cron.log { /home/hans/ics-importer/cron.log {
@@ -139,29 +152,61 @@ Inhalt:
} }
``` ```
Diese Konfiguration rotiert wöchentlich, behält vier alte Versionen, komprimiert alte Logs und legt nach der Rotation eine neue Datei mit passenden Rechten an. [putorius](https://www.putorius.net/rotating-custom-logs-with-logrotate-on.html) Damit wird das Log wöchentlich rotiert, vier Versionen bleiben erhalten und ältere Logs werden komprimiert.
Zum Testen der Konfiguration: ## mailbox.org in Thunderbird
```bash Für das eigentliche Projekt ist Thunderbird nicht zwingend nötig, aber mailbox.org empfiehlt für E-Mail in Thunderbird IMAP und für Kalender CalDAV.[cite:55][cite:45]
sudo logrotate -d /etc/logrotate.d/ics-importer
sudo logrotate -f /etc/logrotate.d/ics-importer
```
## Einfügen in vim-nox ### IMAP in Thunderbird
Wenn `crontab -e` mit Vim geöffnet wird, kann im Insert-Modus oft direkt mit `Strg+Shift+V` aus dem Terminal-Zwischenspeicher eingefügt werden. Wenn Vim mit Clipboard-Unterstützung gebaut wurde, ist im Normal-Modus auch `"+p` zum Einfügen aus der System-Zwischenablage möglich. [reddit](https://www.reddit.com/r/vim/comments/q0fsw4/how_do_i_paste_clipboard_contents_into_vim/) Thunderbird erkennt mailbox.org in der Regel automatisch; empfohlen wird IMAP statt POP3.[cite:55][cite:63]
## Sicherheitshinweise ### CalDAV in Thunderbird
`config.ini` enthält Zugangsdaten und sollte nicht weitergegeben oder in öffentliche Repositories eingecheckt werden. Bei aktivierter Zwei-Faktor-Authentifizierung empfiehlt mailbox.org für externe Anwendungen App-Passwörter beziehungsweise Applikationspasswörter anstelle des normalen Passworts. [kb.mailbox](https://kb.mailbox.org/de/business/adressbuch-und-kalender/caldav-bei-thunderbird/) Kalender lassen sich in Thunderbird über **Datei → Neu → Kalender → Im Netzwerk → CalDAV** einbinden. Als URL dient die vollständige mailbox.org-CalDAV-Adresse des Kalenders.[cite:45][cite:51]
In manchen Setups muss in Thunderbird zusätzlich `calendar.network.multirealm` auf `true` gesetzt werden, damit die Authentifizierung sauber funktioniert.[cite:45][cite:51]
## Sicherheit
`.env` enthält Zugangsdaten im Klartext und darf nicht in ein öffentliches Repository eingecheckt werden. `python-dotenv` ist für lokale Konfigurationsdateien gedacht, ersetzt aber kein Secret-Management-System.[cite:162][cite:164]
Empfehlungen:
- `.env` nur lokal speichern
- `chmod 600 .env` setzen
- `.env` in `.gitignore` eintragen
- Bei aktiver 2FA App-/Applikationspasswörter statt des Hauptpassworts verwenden.[cite:63][cite:45]
## Fehlersuche ## Fehlersuche
Wenn der Cron-Job nicht läuft, sind die häufigsten Ursachen ein falscher Python-Pfad, fehlende Rechte auf Dateien oder abweichende Umgebungsvariablen unter Cron. Cron-Jobs sollten deshalb mit absoluten Pfaden arbeiten, und ein separates Log wie `cron.log` macht Fehler schnell sichtbar. [betterstack](https://betterstack.com/community/guides/logging/how-to-manage-log-files-with-logrotate-on-ubuntu-20-04/) ### IMAP funktioniert nicht
Wenn Termine nicht importiert werden, sollte zuerst geprüft werden, ob die IMAP-Anmeldung funktioniert, ob tatsächlich `.ics`-Anhänge im ausgewählten Ordner vorhanden sind und ob die CalDAV-URL exakt zum Zielkalender gehört. mailbox.org beschreibt, dass die Kalenderadresse direkt aus den Kalendereigenschaften des jeweiligen Kalenders übernommen werden soll. [kb.mailbox](https://kb.mailbox.org/de/privat/e-mail/e-mail-einrichtung-mit-mozilla-thunderbird/) Prüfen:
- `IMAP_HOST=imap.mailbox.org`
- `IMAP_PORT=993`
- vollständige E-Mail-Adresse als Benutzername
- korrektes Passwort oder App-Passwort bei aktiver 2FA.[cite:56][cite:63]
### CalDAV funktioniert nicht
Prüfen:
- vollständige CalDAV-URL aus den Kalendereigenschaften in mailbox.org
- korrekter Benutzername
- korrektes Passwort bzw. Applikationspasswort bei aktiver 2FA.[cite:45][cite:51]
### Cron führt das Skript nicht aus
Prüfen:
- absoluter Python-Pfad aus `pipenv --py`
- absoluter Skriptpfad
- Schreibrechte für `cron.log`
- manueller Testlauf funktioniert bereits
## Empfohlener Betriebsmodus ## Empfohlener Betriebsmodus
Für dieses Setup ist ein stündlicher Cron-Job mit aktiviertem Duplikat-Schutz und `unseen_only = true` ein pragmatischer Standard. Das reduziert unnötige IMAP-Abfragen und passt gut zu einem Postfach, in dem Termine typischerweise per Mail-Anhang eingehen. [naschenweng](https://www.naschenweng.eu/2025/03/29/%F0%9F%93%85-sync-ics-feeds-to-your-caldav-calendar-with-emojis-deduplication-and-docker/) Für die meisten Setups ist `IMAP_UNSEEN_ONLY=true` sinnvoll, damit nur neue bzw. ungelesene Mails geprüft werden. In Verbindung mit dem Hash-basierten Duplikat-Schutz verhindert das unnötige Doppelimporte und reduziert die Last auf dem Postfach.
-17
View File
@@ -1,17 +0,0 @@
[imap]
host = imap.mailbox.org
port = 993
username = minitux@mailbox.org
# Normales Passwort ODER App-Passwort (bei aktiver 2FA zwingend!)
password = 4711Cayenne64
folder = INBOX
# true = nur ungelesene Mails prüfen (empfohlen)
unseen_only = true
# true = verarbeitete Mails als gelesen markieren
mark_as_read = true
[caldav]
# CalDAV-URL aus mailbox.org Office: Kalender → drei Striche → Eigenschaften
url = https://dav.mailbox.org/caldav/Y2FsOi8vMC8zMg
username = minitux@mailbox.org
password = 4711Cayenne64
-17
View File
@@ -1,17 +0,0 @@
[imap]
host = imap.mailbox.org
port = 993
username = ihr-name@mailbox.org
# Normales Passwort ODER App-Passwort (bei aktiver 2FA zwingend!)
password = IHR_PASSWORT_ODER_APP_PASSWORT
folder = INBOX
# true = nur ungelesene Mails prüfen (empfohlen)
unseen_only = true
# true = verarbeitete Mails als gelesen markieren
mark_as_read = false
[caldav]
# CalDAV-URL aus mailbox.org Office: Kalender → drei Striche → Eigenschaften
url = https://dav.mailbox.org/caldav/IHR_KALENDER_ID
username = ihr-name@mailbox.org
password = IHR_PASSWORT_ODER_APP_PASSWORT
+6
View File
@@ -22,3 +22,9 @@
2026-05-12 08:26:10,244 [INFO] ✓ Termin importiert: Sabine [040000008200E00074C5] 2026-05-12 08:26:10,244 [INFO] ✓ Termin importiert: Sabine [040000008200E00074C5]
2026-05-12 08:26:10,244 [INFO] Fertig. 3 Termine insgesamt importiert. 2026-05-12 08:26:10,244 [INFO] Fertig. 3 Termine insgesamt importiert.
2026-05-12 08:26:10,245 [INFO] ============================================================ 2026-05-12 08:26:10,245 [INFO] ============================================================
2026-05-31 09:12:16,921 [INFO] ============================================================
2026-05-31 09:12:16,921 [INFO] ICS-Importer gestartet (2026-05-31T07:12:16.921142+00:00)
2026-05-31 09:12:16,921 [INFO] Verbinde mit IMAP imap.mailbox.org:993 als minitux@mailbox.org ...
2026-05-31 09:12:17,331 [INFO] 0 .ics-Anhang/-Anhänge gefunden.
2026-05-31 09:12:17,331 [INFO] Fertig. 0 Termine insgesamt importiert.
2026-05-31 09:12:17,331 [INFO] ============================================================
+49 -59
View File
@@ -1,81 +1,67 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
ics_mail_importer.py ics_mail_importer_env.py
-------------------- ------------------------
Sucht in einem mailbox.org IMAP-Postfach nach E-Mails mit .ics-Anhängen Sucht in einem mailbox.org IMAP-Postfach nach E-Mails mit .ics-Anhängen
und importiert die enthaltenen Termine automatisch in einen CalDAV-Kalender. und importiert die enthaltenen Termine automatisch in einen CalDAV-Kalender.
Benötigte Pakete: Konfiguration über .env-Datei mit python-dotenv.
pipenv install caldav icalendar
Einrichtung:
1. config.ini ausfüllen (liegt im gleichen Verzeichnis)
2. Optional: Als Cronjob einrichten (z.B. alle 30 Minuten)
*/30 * * * * /pfad/zu/python3 /pfad/zum/ics_mail_importer.py
""" """
import imaplib import imaplib
import email import email
import os
import logging import logging
import hashlib import hashlib
import configparser import os
from pathlib import Path from pathlib import Path
from datetime import datetime, timezone from datetime import datetime, timezone
from dotenv import load_dotenv
import caldav import caldav
from icalendar import Calendar from icalendar import Calendar
# ─────────────────────────── Logging ─────────────────────────────────────────── BASE_DIR = Path(__file__).resolve().parent
LOG_FILE = Path(__file__).parent / "ics_importer.log" load_dotenv(BASE_DIR / ".env")
LOG_FILE = BASE_DIR / "ics_importer.log"
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s", format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[ handlers=[logging.FileHandler(LOG_FILE), logging.StreamHandler()],
logging.FileHandler(LOG_FILE),
logging.StreamHandler(),
],
) )
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# ─────────────────────────── Konfiguration laden ─────────────────────────────── SEEN_FILE = BASE_DIR / "imported_uids.txt"
CONFIG_FILE = Path(__file__).parent / "config.ini"
def load_config():
if not CONFIG_FILE.exists():
log.error("config.ini nicht gefunden. Bitte config.ini.example umbenennen und ausfüllen.")
raise FileNotFoundError(str(CONFIG_FILE))
cfg = configparser.ConfigParser()
cfg.read(CONFIG_FILE)
return cfg
# ─────────────────────────── Duplikat-Tracking ────────────────────────────────
SEEN_FILE = Path(__file__).parent / "imported_uids.txt"
def load_seen_uids(): def load_seen_uids():
if not SEEN_FILE.exists(): if not SEEN_FILE.exists():
return set() return set()
return set(SEEN_FILE.read_text().splitlines()) return set(SEEN_FILE.read_text().splitlines())
def save_uid(uid: str): def save_uid(uid: str):
with SEEN_FILE.open("a") as f: with SEEN_FILE.open("a") as f:
f.write(uid + "\n") f.write(uid + "\n")
# ─────────────────────────── IMAP-Anhänge holen ───────────────────────────────
def fetch_ics_attachments(cfg): def fetch_ics_attachments():
host = cfg["imap"]["host"] host = os.getenv("IMAP_HOST", "imap.mailbox.org")
port = int(cfg["imap"].get("port", "993")) port = int(os.getenv("IMAP_PORT", "993"))
username = cfg["imap"]["username"] username = os.getenv("IMAP_USERNAME")
password = cfg["imap"]["password"] password = os.getenv("IMAP_PASSWORD")
folder = cfg["imap"].get("folder", "INBOX") folder = os.getenv("IMAP_FOLDER", "INBOX")
if not username or not password:
raise RuntimeError("IMAP_USERNAME oder IMAP_PASSWORD fehlt in .env")
log.info(f"Verbinde mit IMAP {host}:{port} als {username} ...") log.info(f"Verbinde mit IMAP {host}:{port} als {username} ...")
conn = imaplib.IMAP4_SSL(host, port) conn = imaplib.IMAP4_SSL(host, port)
conn.login(username, password) conn.login(username, password)
conn.select(folder) conn.select(folder)
search_unseen_only = cfg["imap"].getboolean("unseen_only", fallback=True) unseen_only = os.getenv("IMAP_UNSEEN_ONLY", "true").lower() == "true"
criteria = "(UNSEEN)" if search_unseen_only else "ALL" criteria = "(UNSEEN)" if unseen_only else "ALL"
_, msg_ids = conn.search(None, criteria) _, msg_ids = conn.search(None, criteria)
found = [] found = []
@@ -85,12 +71,10 @@ def fetch_ics_attachments(cfg):
msg = email.message_from_bytes(raw) msg = email.message_from_bytes(raw)
for part in msg.walk(): for part in msg.walk():
ct = part.get_content_type() ct = part.get_content_type()
fn = part.get_filename() or "" fn = part.get_filename() or ""
is_ics = ct in ("text/calendar", "application/ics") or fn.lower().endswith(
is_ics = ( ".ics"
ct in ("text/calendar", "application/ics")
or fn.lower().endswith(".ics")
) )
if not is_ics: if not is_ics:
continue continue
@@ -103,7 +87,8 @@ def fetch_ics_attachments(cfg):
log.info(f" ics-Anhang gefunden: {fn!r} (Hash {uid_hash[:12]}…)") log.info(f" ics-Anhang gefunden: {fn!r} (Hash {uid_hash[:12]}…)")
found.append((uid_hash, ics_bytes)) found.append((uid_hash, ics_bytes))
if cfg["imap"].getboolean("mark_as_read", fallback=False): mark_read = os.getenv("IMAP_MARK_AS_READ", "false").lower() == "true"
if mark_read:
conn.store(mid, "+FLAGS", "\\Seen") conn.store(mid, "+FLAGS", "\\Seen")
conn.close() conn.close()
@@ -111,13 +96,18 @@ def fetch_ics_attachments(cfg):
log.info(f" {len(found)} .ics-Anhang/-Anhänge gefunden.") log.info(f" {len(found)} .ics-Anhang/-Anhänge gefunden.")
return found return found
# ─────────────────────────── CalDAV-Import ────────────────────────────────────
def import_to_caldav(cfg, ics_bytes: bytes, uid_hash: str):
caldav_url = cfg["caldav"]["url"]
username = cfg["caldav"]["username"]
password = cfg["caldav"]["password"]
client = caldav.DAVClient(url=caldav_url, username=username, password=password) def import_to_caldav(ics_bytes: bytes, uid_hash: str):
caldav_url = os.getenv("CALDAV_URL")
username = os.getenv("CALDAV_USERNAME")
password = os.getenv("CALDAV_PASSWORD")
if not caldav_url or not username or not password:
raise RuntimeError(
"CALDAV_URL, CALDAV_USERNAME oder CALDAV_PASSWORD fehlt in .env"
)
client = caldav.DAVClient(url=caldav_url, username=username, password=password)
calendar = client.calendar(url=caldav_url) calendar = client.calendar(url=caldav_url)
cal = Calendar.from_ical(ics_bytes) cal = Calendar.from_ical(ics_bytes)
@@ -135,35 +125,35 @@ def import_to_caldav(cfg, ics_bytes: bytes, uid_hash: str):
uid = str(component.get("uid", uid_hash + f"-{imported}")) uid = str(component.get("uid", uid_hash + f"-{imported}"))
try: try:
calendar.add_event(single_cal.to_ical().decode("utf-8")) calendar.add_event(single_cal.to_ical().decode("utf-8"))
log.info(f" ✓ Termin importiert: {component.get('summary', '(kein Titel)')} [{uid[:20]}]") log.info(
f" ✓ Termin importiert: {component.get('summary', '(kein Titel)')} [{uid[:20]}]"
)
imported += 1 imported += 1
except Exception as e: except Exception as e:
log.warning(f" ✗ Fehler beim Import von {uid[:20]}: {e}") log.warning(f" ✗ Fehler beim Import von {uid[:20]}: {e}")
return imported return imported
# ─────────────────────────── Hauptprogramm ────────────────────────────────────
def main(): def main():
log.info("=" * 60) log.info("=" * 60)
log.info(f"ICS-Importer gestartet ({datetime.now(timezone.utc).isoformat()})") log.info(f"ICS-Importer gestartet ({datetime.now(timezone.utc).isoformat()})")
cfg = load_config()
seen_uids = load_seen_uids() seen_uids = load_seen_uids()
attachments = fetch_ics_attachments()
attachments = fetch_ics_attachments(cfg)
total_imported = 0 total_imported = 0
for uid_hash, ics_bytes in attachments: for uid_hash, ics_bytes in attachments:
if uid_hash in seen_uids: if uid_hash in seen_uids:
log.info(f" Überspringe bereits importierten Anhang {uid_hash[:12]}") log.info(f" Überspringe bereits importierten Anhang {uid_hash[:12]}")
continue continue
n = import_to_caldav(ics_bytes, uid_hash)
n = import_to_caldav(cfg, ics_bytes, uid_hash)
total_imported += n total_imported += n
save_uid(uid_hash) save_uid(uid_hash)
log.info(f"Fertig. {total_imported} Termine insgesamt importiert.") log.info(f"Fertig. {total_imported} Termine insgesamt importiert.")
log.info("=" * 60) log.info("=" * 60)
if __name__ == "__main__": if __name__ == "__main__":
main() main()