[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fKT8Qk1O-o1AsoX1C8l0kMNSxQoQSivxPIg1rp4sDZYU":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":51,"_status":50},375,"Why is the `zid` important when adding a folder share in Zimbra?","The `zid` is the unique identifier returned in the successful SOAP response for the shared folder. It is used to manage or revoke the share later. The article’s code extracts this ID using regex, which is essential for tracking shared folders. Similar response handling is seen in [Zimbra SOAP API Development Guide 5 - Email Forwarding](\u002Fnews\u002Fzimbra-soap-api-development-guide-5-email-forwarding).","\u003Cp>The `zid` is the unique identifier returned in the successful SOAP response for the shared folder. It is used to manage or revoke the share later. The article’s code extracts this ID using regex, which is essential for tracking shared folders. Similar response handling is seen in [Zimbra SOAP API Development Guide 5 - Email Forwarding](\u002Fnews\u002Fzimbra-soap-api-development-guide-5-email-forwarding).\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fzimbra-soap-api-development-guide-4-email-export-and-folder-sharing\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","why-is-the-zid-important-when-adding-a-folder-share-in-zimbra-1777484047190","zid, folder sharing, SOAP response, regex, share management",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":47,"updatedAt":48,"createdAt":49,"_status":50},94,"Zimbra SOAP API Development Guide 4 - Email Export and Folder Sharing","zimbra-soap-api-development-guide-4-email-export-and-folder-sharing","Learn to implement Zimbra SOAP API email export with filters and folder sharing. Includes code examples for automation and advanced configurations.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will further expand the functionality of the open-source code Zimbra_SOAP_API_Manage to implement email export and folder sharing, and share development details.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Email Export\u003C\u002Fli>\u003Cli>Folder Sharing\u003C\u002Fli>\u003Cli>Open-Source Code\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Email Export\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Zimbra supports exporting all emails from the current mailbox. The operation method through the web interface is as follows:\u003C\u002Fp>\u003Cp>After logging into the mailbox, navigate to Preferences-&gt;Import\u002FExport, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770018735118_0_9988c30748.jpeg\">\u003C\u002Fp>\u003Cp>Next, analyze the implementation process through packet capture, then use a program to implement this functionality.\u003C\u002Fp>\u003Ch3>1. Export emails with default configuration\u003C\u002Fh3>\u003Cp>Under default configuration, all emails will be exported and saved as a compressed archive.\u003C\u002Fp>\u003Cp>Example access URL:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>https:\u002F\u002F192.168.1.1\u002Fhome\u002Fadmin%40test.com\u002F?fmt=tgz&amp;filename=All-2022-07-27-181056&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Parameter analysis:\u003C\u002Fp>\u003Cul>\u003Cli>admin%40test.com is the mailbox user, which can be replaced with ~\u003C\u002Fli>\u003Cli>filename=All-2022-07-27-181056 is the filename saved when records exist. 2022-07-27-181056 corresponds to the time format year-month-day-hourminutesecond. The time includes timezone and requires time difference calculation.\u003C\u002Fli>\u003Cli>emptyname=No+Data+to+Export is the filename saved when records are empty.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>In program implementation, the format must be consistent with web operations. Code details:\u003C\u002Fp>\u003Ch4>(1) Construct the saved filename\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>from time import localtime, strftime\u003Cbr>exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>filename = \"All-\" + str(exporttime)\u003Cbr>print(filename)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) Save file\u003C\u002Fh4>\u003Cp>Use binary write when saving the file\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>with open(path, 'wb+') as file_object:\u003Cbr>    file_object.write(r.content)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def exportmailall_request(uri,token,mailbox):\u003Cbr>    from time import localtime, strftime\u003Cbr>    exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>    filename = \"All-\" + str(exporttime)\u003Cbr>    url = uri + \"\u002Fhome\u002F\" + mailbox + \"\u002F?fmt=tgz&amp;filename=\" + filename + \"&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\"\u003Cbr>    headers[\"Cookie\"]=\"ZM_AUTH_TOKEN=\"+token+\";\"\u003Cbr>    r = requests.get(url,headers=headers,verify=False)\u003Cbr>\u003Cbr>    if r.status_code == 200:\u003Cbr>        print(\"[*] Try to export the mail\")\u003Cbr>        path = filename + \".tgz\"\u003Cbr>        with open(path, 'wb+') as file_object:\u003Cbr>            file_object.write(r.content)\u003Cbr>        print(\"[+] Save as \" + path)\u003Cbr>    else:\u003Cbr>        print(\"[!]\")\u003Cbr>        print(r.status_code)\u003Cbr>        print(r.text)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>2. Add filter conditions to export emails\u003C\u002Fh3>\u003Cp>Under advanced options, you can add filter conditions to export specific emails\u003C\u002Fp>\u003Cp>Example access URL:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>https:\u002F\u002F192.168.1.1\u002Fhome\u002Fadmin%40test.com\u002F?fmt=tgz&amp;start=1658818800000&amp;end=1658991600000&amp;query=content%3Apassword&amp;filename=All-2022-07-27-193148&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Parameter analysis, the following parameters have been added:\u003C\u002Fp>\u003Cul>\u003Cli>start=1658818800000 is the start time for filtering, in Unix timestamp format, with no additional time difference calculation\u003C\u002Fli>\u003Cli>end=1658991600000 is the end time for filtering, in Unix timestamp format, with no additional time difference calculation\u003C\u002Fli>\u003Cli>query=content%3Apassword is the keyword for filtering, used to query emails with the keyword 'password' in the body\u003C\u002Fli>\u003C\u002Ful>\u003Cp>For the syntax of filter conditions, refer to: https:\u002F\u002Fwiki.zimbra.com\u002Fwiki\u002FZimbra_Web_Client_Search_Tips\u003C\u002Fp>\u003Cp>Code implementation details:\u003C\u002Fp>\u003Ch4>(1) Example code for time format conversion\u003C\u002Fh4>\u003Cp>Convert time to seconds:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>import datetime, time\u003Cbr>search1 = datetime.datetime(2022, 7, 26)\u003Cbr>search1Toseconds = int(time.mktime(search1.timetuple()))\u003Cbr>print(search1Toseconds)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Convert seconds to time:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>from datetime import datetime\u003Cbr>search1ToDate = str(datetime.fromtimestamp(search1Toseconds))\u003Cbr>print(search1ToDate)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Implementation code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def exportmail_request(uri,token,mailbox):\u003Cbr>    url = uri + \"\u002Fhome\u002F\" + mailbox + \"\u002F?fmt=tgz\"\u003Cbr>    print(\"[*] Advanced settings\")\u003Cbr>    print(\"    You can set the following:\")\u003Cbr>    print(\"    - start time:      eg:  2022-06-01\")\u003Cbr>    print(\"                       eg:  null\")\u003Cbr>    print(\"    - end   time:      eg:  2022-06-02\")\u003Cbr>    print(\"    - search filter:   eg:  content:keyword\")\u003Cbr>    print(\"[*] Input the start time:\")\u003Cbr>    starttime = input(\"[&gt;]: \")\u003Cbr>    \u003Cbr>    if len(starttime) != 0:\u003Cbr>        if starttime != \"null\":\u003Cbr>            starttimelist = starttime.split('-')\u003Cbr>            import datetime, time\u003Cbr>            search1 = datetime.datetime(int(starttimelist[0]), int(starttimelist[1]), int(starttimelist[2]))\u003Cbr>            search1Toseconds = int(time.mktime(search1.timetuple()))\u003Cbr>            print(\"[*] Input the end time:\")\u003Cbr>            endtime = input(\"[&gt;]: \")\u003Cbr>            if len(endtime) != 0:\u003Cbr>                endtimelist = endtime.split('-')\u003Cbr>                search2 = datetime.datetime(int(endtimelist[0]), int(endtimelist[1]), int(endtimelist[2]))\u003Cbr>                search2Toseconds = int(time.mktime(search2.timetuple()))\u003Cbr>                url = url + \"&amp;start=\" + str(search1Toseconds) + \"000&amp;end=\" + str(search2Toseconds) + \"000\"\u003Cbr>            else:\u003Cbr>                url = url + \"&amp;start=\" + str(search1Toseconds) + \"000\"\u003Cbr>        else:\u003Cbr>            print(\"[*] Search all time\")\u003Cbr>    else:\u003Cbr>        print(\"[*] Search all time\")\u003Cbr>    print(\"[*] Input the search filter:\")\u003Cbr>    searchfilter = input(\"[&gt;]: \")\u003Cbr>    \u003Cbr>    from time import localtime, strftime\u003Cbr>    exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>    filename = \"All-\" + str(exporttime)\u003Cbr>\u003Cbr>    url = url + \"&amp;query=\" + searchfileter + \"&amp;filename=\" + filename + \"&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\"\u003Cbr>    print(\"[*] Export url:\" + url)\u003Cbr>    headers[\"Cookie\"]=\"ZM_AUTH_TOKEN=\"+token+\";\"\u003Cbr>    r = requests.get(url,headers=headers,verify=False)\u003Cbr>\u003Cbr>    if r.status_code == 200:        \u003Cbr>        print(\"[*] Try to export the mail\")\u003Cbr>        path = filename + \".tgz\"        \u003Cbr>        with open(path, 'wb+') as file_object:\u003Cbr>            file_object.write(r.content)\u003Cbr>        print(\"[+] Save as \" + path)\u003Cbr>    else:\u003Cbr>        print(\"[!]\")\u003Cbr>        print(r.status_code)\u003Cbr>        print(r.text)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x03 Folder Sharing\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Process Analysis\u003C\u002Fh3>\u003Cp>Zimbra supports sharing the current mailbox's folders with other users. The operation method through the web interface is as follows:\u003C\u002Fp>\u003Cp>After logging into the mailbox, select Preferences-&gt;Sharing in sequence, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770018746204_1_e4cdbe50fb.jpeg\">\u003C\u002Fp>\u003Cp>The following three folders can be selected for sharing:\u003C\u002Fp>\u003Cul>\u003Cli>Inbox\u003C\u002Fli>\u003Cli>Sent\u003C\u002Fli>\u003Cli>Junk\u003C\u002Fli>\u003C\u002Ful>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770018753911_2_cb2aef029d.jpeg\">\u003C\u002Fp>\u003Cp>Set sharing properties as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770018765646_3_67505961eb.jpeg\">\u003C\u002Fp>\u003Cp>The following settings need to be distinguished:\u003C\u002Fp>\u003Ch4>(1) Role\u003C\u002Fh4>\u003Cul>\u003Cli>Viewer can only view emails\u003C\u002Fli>\u003Cli>Manager can modify emails\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>(2) Message\u003C\u002Fh4>\u003Cul>\u003Cli>Send standard message: After configuration, a confirmation email will be sent to the destination mailbox\u003C\u002Fli>\u003Cli>Do not send mail about this share: No confirmation email will be sent\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Here, packet capture can be used to analyze the specific values corresponding to each setting\u003C\u002Fp>\u003Cp>Example packet 1:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Csoap:body>\u003Cbr>\u003Cbatchrequest xmlns=\"urn:zimbra\" onerror=\"continue\">\u003Cbr>\u003Cfolderactionrequest xmlns=\"urn:zimbraMail\" requestid=\"0\">\u003Cbr>\u003Caction op=\"grant\" id=\"2\">\u003Cbr>\u003Cgrant gt=\"usr\" inh=\"1\" d=\"test1@test.com\" perm=\"r\" pw=\"\">\u003Cbr>\u003C\u002Fgrant>\u003C\u002Faction>\u003Cbr>\u003C\u002Ffolderactionrequest>\u003Cbr>\u003C\u002Fbatchrequest>\u003Cbr>\u003C\u002Fsoap:body>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Format Analysis:\u003C\u002Fp>\u003Ch4>(1)\u003Caction op=\"grant\" id=\"2\">\u003C\u002Faction>\u003C\u002Fh4>\u003Cp>id=\"2\" indicates Inbox\u003C\u002Fp>\u003Cp>Sent corresponds to id=\"5\"\u003C\u002Fp>\u003Cp>Junk corresponds to id=\"4\"\u003C\u002Fp>\u003Cp>Through testing, Drafts can also be specified, corresponding to id=\"6\"\u003C\u002Fp>\u003Ch4>(2)\u003Cgrant gt=\"usr\" inh=\"1\" d=\"test1@test.com\" perm=\"r\" pw=\"\">\u003C\u002Fgrant>\u003C\u002Fh4>\u003Cp>d=\"test1@test.com\" indicates the mailbox that can access the shared folder\u003C\u002Fp>\u003Cp>perm=\"r\" indicates read permission, corresponding to Viewer\u003C\u002Fp>\u003Cp>Manager corresponds to the configuration perm=\"rwidx\", indicating read, write, insert, and delete permissions\u003C\u002Fp>\u003Cp>If Send standard message is set, a confirmation email will be sent to the target mailbox (e.g., test1@test.com) after configuration. Example data packet format:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Csoap:body>\u003Cbr>\u003Csendsharenotificationrequest xmlns=\"urn:zimbraMail\">\u003Cbr>\u003Citem id=\"2\">\u003Cbr>\u003Ce a=\"test1@test.com\">\u003Cbr>\u003Cnotes>\u003C\u002Fnotes>\u003Cbr>\u003C\u002Fe>\u003C\u002Fitem>\u003C\u002Fsendsharenotificationrequest>\u003Cbr>\u003C\u002Fsoap:body>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Mailbox test1@test.com will receive an email to confirm whether to accept folder sharing\u003C\u002Fp>\u003Ch3>2. Code Implementation\u003C\u002Fh3>\u003Ch4>(1) Add File Sharing\u003C\u002Fh4>\u003Cp>Need to specify the target mailbox and shared folder\u003C\u002Fp>\u003Cp>The successful response for adding file sharing returns the zid corresponding to the shared folder\u003C\u002Fp>\u003Cp>Implementation code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def addshare_request(uri,token):\u003Cbr>    print(\"[*] Input the target mailbox:\")\u003Cbr>    mailbox = input(\"[&gt;]: \")\u003Cbr>    print(\"[*] Input the share folder:\")\u003Cbr>    print(\"    2     Inbox\")\u003Cbr>    print(\"    4     Junk\")\u003Cbr>    print(\"    5     Sent\")\u003Cbr>    print(\"    6     Drafts\")\u003Cbr>\u003Cbr>    folder = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Cbatchrequest xmlns=\"urn:zimbra\" onerror=\"continue\">\u003Cbr>                \u003Cfolderactionrequest xmlns=\"urn:zimbraMail\" requestid=\"0\">\u003Cbr>                \u003Caction op=\"grant\" id=\"{folder}\">\u003Cbr>                \u003Cgrant gt=\"usr\" inh=\"1\" d=\"{mailbox}\" perm=\"rwidx\" pw=\"\">\u003Cbr>                \u003C\u002Fgrant>\u003C\u002Faction>\u003Cbr>                \u003C\u002Ffolderactionrequest>\u003Cbr>            \u003C\u002Fbatchrequest>\u003Cbr>       \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,folder=folder,mailbox=mailbox),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200 and 'zid' in r.text:        \u003Cbr>            pattern_id = re.compile(r\"zid=\\\"(.*?)\\\"\")\u003Cbr>            zid = pattern_id.findall(r.text)[0] \u003Cbr>            print(\"[+] Add success\")\u003Cbr>            print(\"    zid: %s\"%(zid))\u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) Send file sharing request\u003C\u002Fh4>\u003Cp>Requires specifying the target mailbox\u003C\u002Fp>\u003Cp>Code implementation example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def sendsharenotification_request(uri,token):\u003Cbr>    print(\"[*] Input the target mailbox:\")\u003Cbr>    mailbox = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Csendsharenotificationrequest xmlns=\"urn:zimbraMail\">\u003Cbr>            \u003Citem id=\"2\">\u003Cbr>            \u003Ce a=\"{mailbox}\">\u003Cbr>            \u003Cnotes>\u003C\u002Fnotes>\u003Cbr>            \u003C\u002Fe>\u003C\u002Fitem>\u003C\u002Fsendsharenotificationrequest>\u003Cbr>        \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,mailbox=mailbox),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200:   \u003Cbr>            print(\"[+] Send success\")\u003Cbr>        elif r.status_code == 500 and 'no matching grant' in r.text:\u003Cbr>            print(\"[-] You should add share first.\")\u003Cbr>\u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Note: Only after adding a file share can sending a file share request successfully return 200; otherwise, it returns 500 with the message 'invalid request: no matching grant'.\u003C\u002Fp>\u003Ch4>(3) Delete file share\u003C\u002Fh4>\u003Cp>Requires specifying the zid and shared folder corresponding to the target email. The zid can be obtained from the successful response of adding a file share.\u003C\u002Fp>\u003Cp>Example implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def removeshare_request(uri,token):\u003Cbr>    print(\"[*] Input the zid:\")\u003Cbr>    zid = input(\"[&gt;]: \")\u003Cbr>    print(\"[*] Input the share folder:\")\u003Cbr>    print(\"    2     Inbox\")\u003Cbr>    print(\"    4     Junk\")\u003Cbr>    print(\"    5     Sent\")\u003Cbr>    print(\"    6     Drafts\")\u003Cbr>\u003Cbr>    folder = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Cfolderactionrequest xmlns=\"urn:zimbraMail\">\u003Cbr>            \u003Caction op=\"!grant\" id=\"{folder}\" zid=\"{zid}\">\u003Cbr>            \u003C\u002Faction>\u003C\u002Ffolderactionrequest>\u003Cbr>       \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,folder=folder,zid=zid),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200:        \u003Cbr>            print(\"[+] Send success\") \u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Open Source Code\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>New code has been uploaded to GitHub at the following address:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Add the following five features:\u003C\u002Fp>\u003Cul>\u003Cli>AddShare: Add folder sharing with default permissions rwidx\u003C\u002Fli>\u003Cli>ExportMail: Export emails with search criteria, allowing specification of date and keywords\u003C\u002Fli>\u003Cli>ExportMailAll: Export all emails\u003C\u002Fli>\u003Cli>RemoveShare: Remove folder sharing for the current mailbox\u003C\u002Fli>\u003Cli>SendShareNotification: After adding folder sharing, send a confirmation email to the target mailbox\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article expands the invocation methods of the Zimbra SOAP API, adding five practical features. The implementation methods and ideas can also be tested on XSS vulnerabilities.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will further expand the functionality of the open-source code Zimbra_SOAP_API_Manage to implement email export and folder sharing, and share development details.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Email Export\u003C\u002Fli>\u003Cli>Folder Sharing\u003C\u002Fli>\u003Cli>Open-Source Code\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Email Export\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Zimbra supports exporting all emails from the current mailbox. The operation method through the web interface is as follows:\u003C\u002Fp>\u003Cp>After logging into the mailbox, navigate to Preferences-&gt;Import\u002FExport, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770018735118_0_9988c30748-1.jpeg\">\u003C\u002Fp>\u003Cp>Next, analyze the implementation process through packet capture, then use a program to implement this functionality.\u003C\u002Fp>\u003Ch3>1. Export emails with default configuration\u003C\u002Fh3>\u003Cp>Under default configuration, all emails will be exported and saved as a compressed archive.\u003C\u002Fp>\u003Cp>Example access URL:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>https:\u002F\u002F192.168.1.1\u002Fhome\u002Fadmin%40test.com\u002F?fmt=tgz&amp;filename=All-2022-07-27-181056&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Parameter analysis:\u003C\u002Fp>\u003Cul>\u003Cli>admin%40test.com is the mailbox user, which can be replaced with ~\u003C\u002Fli>\u003Cli>filename=All-2022-07-27-181056 is the filename saved when records exist. 2022-07-27-181056 corresponds to the time format year-month-day-hourminutesecond. The time includes timezone and requires time difference calculation.\u003C\u002Fli>\u003Cli>emptyname=No+Data+to+Export is the filename saved when records are empty.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>In program implementation, the format must be consistent with web operations. Code details:\u003C\u002Fp>\u003Ch4>(1) Construct the saved filename\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>from time import localtime, strftime\u003Cbr>exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>filename = \"All-\" + str(exporttime)\u003Cbr>print(filename)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) Save file\u003C\u002Fh4>\u003Cp>Use binary write when saving the file\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>with open(path, 'wb+') as file_object:\u003Cbr>    file_object.write(r.content)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def exportmailall_request(uri,token,mailbox):\u003Cbr>    from time import localtime, strftime\u003Cbr>    exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>    filename = \"All-\" + str(exporttime)\u003Cbr>    url = uri + \"\u002Fhome\u002F\" + mailbox + \"\u002F?fmt=tgz&amp;filename=\" + filename + \"&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\"\u003Cbr>    headers[\"Cookie\"]=\"ZM_AUTH_TOKEN=\"+token+\";\"\u003Cbr>    r = requests.get(url,headers=headers,verify=False)\u003Cbr>\u003Cbr>    if r.status_code == 200:\u003Cbr>        print(\"[*] Try to export the mail\")\u003Cbr>        path = filename + \".tgz\"\u003Cbr>        with open(path, 'wb+') as file_object:\u003Cbr>            file_object.write(r.content)\u003Cbr>        print(\"[+] Save as \" + path)\u003Cbr>    else:\u003Cbr>        print(\"[!]\")\u003Cbr>        print(r.status_code)\u003Cbr>        print(r.text)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>2. Add filter conditions to export emails\u003C\u002Fh3>\u003Cp>Under advanced options, you can add filter conditions to export specific emails\u003C\u002Fp>\u003Cp>Example access URL:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>https:\u002F\u002F192.168.1.1\u002Fhome\u002Fadmin%40test.com\u002F?fmt=tgz&amp;start=1658818800000&amp;end=1658991600000&amp;query=content%3Apassword&amp;filename=All-2022-07-27-193148&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Parameter analysis, the following parameters have been added:\u003C\u002Fp>\u003Cul>\u003Cli>start=1658818800000 is the start time for filtering, in Unix timestamp format, with no additional time difference calculation\u003C\u002Fli>\u003Cli>end=1658991600000 is the end time for filtering, in Unix timestamp format, with no additional time difference calculation\u003C\u002Fli>\u003Cli>query=content%3Apassword is the keyword for filtering, used to query emails with the keyword 'password' in the body\u003C\u002Fli>\u003C\u002Ful>\u003Cp>For the syntax of filter conditions, refer to: https:\u002F\u002Fwiki.zimbra.com\u002Fwiki\u002FZimbra_Web_Client_Search_Tips\u003C\u002Fp>\u003Cp>Code implementation details:\u003C\u002Fp>\u003Ch4>(1) Example code for time format conversion\u003C\u002Fh4>\u003Cp>Convert time to seconds:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>import datetime, time\u003Cbr>search1 = datetime.datetime(2022, 7, 26)\u003Cbr>search1Toseconds = int(time.mktime(search1.timetuple()))\u003Cbr>print(search1Toseconds)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Convert seconds to time:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>from datetime import datetime\u003Cbr>search1ToDate = str(datetime.fromtimestamp(search1Toseconds))\u003Cbr>print(search1ToDate)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Implementation code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def exportmail_request(uri,token,mailbox):\u003Cbr>    url = uri + \"\u002Fhome\u002F\" + mailbox + \"\u002F?fmt=tgz\"\u003Cbr>    print(\"[*] Advanced settings\")\u003Cbr>    print(\"    You can set the following:\")\u003Cbr>    print(\"    - start time:      eg:  2022-06-01\")\u003Cbr>    print(\"                       eg:  null\")\u003Cbr>    print(\"    - end   time:      eg:  2022-06-02\")\u003Cbr>    print(\"    - search filter:   eg:  content:keyword\")\u003Cbr>    print(\"[*] Input the start time:\")\u003Cbr>    starttime = input(\"[&gt;]: \")\u003Cbr>    \u003Cbr>    if len(starttime) != 0:\u003Cbr>        if starttime != \"null\":\u003Cbr>            starttimelist = starttime.split('-')\u003Cbr>            import datetime, time\u003Cbr>            search1 = datetime.datetime(int(starttimelist[0]), int(starttimelist[1]), int(starttimelist[2]))\u003Cbr>            search1Toseconds = int(time.mktime(search1.timetuple()))\u003Cbr>            print(\"[*] Input the end time:\")\u003Cbr>            endtime = input(\"[&gt;]: \")\u003Cbr>            if len(endtime) != 0:\u003Cbr>                endtimelist = endtime.split('-')\u003Cbr>                search2 = datetime.datetime(int(endtimelist[0]), int(endtimelist[1]), int(endtimelist[2]))\u003Cbr>                search2Toseconds = int(time.mktime(search2.timetuple()))\u003Cbr>                url = url + \"&amp;start=\" + str(search1Toseconds) + \"000&amp;end=\" + str(search2Toseconds) + \"000\"\u003Cbr>            else:\u003Cbr>                url = url + \"&amp;start=\" + str(search1Toseconds) + \"000\"\u003Cbr>        else:\u003Cbr>            print(\"[*] Search all time\")\u003Cbr>    else:\u003Cbr>        print(\"[*] Search all time\")\u003Cbr>    print(\"[*] Input the search filter:\")\u003Cbr>    searchfilter = input(\"[&gt;]: \")\u003Cbr>    \u003Cbr>    from time import localtime, strftime\u003Cbr>    exporttime = strftime(\"%Y-%m-%d-%H%M%S\", localtime())\u003Cbr>    filename = \"All-\" + str(exporttime)\u003Cbr>\u003Cbr>    url = url + \"&amp;query=\" + searchfileter + \"&amp;filename=\" + filename + \"&amp;emptyname=No+Data+to+Export&amp;charset=UTF-8&amp;callback=ZmImportExportController.exportErrorCallback__export1\"\u003Cbr>    print(\"[*] Export url:\" + url)\u003Cbr>    headers[\"Cookie\"]=\"ZM_AUTH_TOKEN=\"+token+\";\"\u003Cbr>    r = requests.get(url,headers=headers,verify=False)\u003Cbr>\u003Cbr>    if r.status_code == 200:        \u003Cbr>        print(\"[*] Try to export the mail\")\u003Cbr>        path = filename + \".tgz\"        \u003Cbr>        with open(path, 'wb+') as file_object:\u003Cbr>            file_object.write(r.content)\u003Cbr>        print(\"[+] Save as \" + path)\u003Cbr>    else:\u003Cbr>        print(\"[!]\")\u003Cbr>        print(r.status_code)\u003Cbr>        print(r.text)\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x03 Folder Sharing\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Process Analysis\u003C\u002Fh3>\u003Cp>Zimbra supports sharing the current mailbox's folders with other users. The operation method through the web interface is as follows:\u003C\u002Fp>\u003Cp>After logging into the mailbox, select Preferences-&gt;Sharing in sequence, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770018746204_1_e4cdbe50fb-1.jpeg\">\u003C\u002Fp>\u003Cp>The following three folders can be selected for sharing:\u003C\u002Fp>\u003Cul>\u003Cli>Inbox\u003C\u002Fli>\u003Cli>Sent\u003C\u002Fli>\u003Cli>Junk\u003C\u002Fli>\u003C\u002Ful>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770018753911_2_cb2aef029d-1.jpeg\">\u003C\u002Fp>\u003Cp>Set sharing properties as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770018765646_3_67505961eb-1.jpeg\">\u003C\u002Fp>\u003Cp>The following settings need to be distinguished:\u003C\u002Fp>\u003Ch4>(1) Role\u003C\u002Fh4>\u003Cul>\u003Cli>Viewer can only view emails\u003C\u002Fli>\u003Cli>Manager can modify emails\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>(2) Message\u003C\u002Fh4>\u003Cul>\u003Cli>Send standard message: After configuration, a confirmation email will be sent to the destination mailbox\u003C\u002Fli>\u003Cli>Do not send mail about this share: No confirmation email will be sent\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Here, packet capture can be used to analyze the specific values corresponding to each setting\u003C\u002Fp>\u003Cp>Example packet 1:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Csoap:body>\u003Cbr>\u003Cbatchrequest xmlns=\"urn:zimbra\" onerror=\"continue\">\u003Cbr>\u003Cfolderactionrequest xmlns=\"urn:zimbraMail\" requestid=\"0\">\u003Cbr>\u003Caction op=\"grant\" id=\"2\">\u003Cbr>\u003Cgrant gt=\"usr\" inh=\"1\" d=\"test1@test.com\" perm=\"r\" pw=\"\">\u003Cbr>\u003C\u002Fgrant>\u003C\u002Faction>\u003Cbr>\u003C\u002Ffolderactionrequest>\u003Cbr>\u003C\u002Fbatchrequest>\u003Cbr>\u003C\u002Fsoap:body>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Format Analysis:\u003C\u002Fp>\u003Ch4>(1)\u003Caction op=\"grant\" id=\"2\">\u003C\u002Faction>\u003C\u002Fh4>\u003Cp>id=\"2\" indicates Inbox\u003C\u002Fp>\u003Cp>Sent corresponds to id=\"5\"\u003C\u002Fp>\u003Cp>Junk corresponds to id=\"4\"\u003C\u002Fp>\u003Cp>Through testing, Drafts can also be specified, corresponding to id=\"6\"\u003C\u002Fp>\u003Ch4>(2)\u003Cgrant gt=\"usr\" inh=\"1\" d=\"test1@test.com\" perm=\"r\" pw=\"\">\u003C\u002Fgrant>\u003C\u002Fh4>\u003Cp>d=\"test1@test.com\" indicates the mailbox that can access the shared folder\u003C\u002Fp>\u003Cp>perm=\"r\" indicates read permission, corresponding to Viewer\u003C\u002Fp>\u003Cp>Manager corresponds to the configuration perm=\"rwidx\", indicating read, write, insert, and delete permissions\u003C\u002Fp>\u003Cp>If Send standard message is set, a confirmation email will be sent to the target mailbox (e.g., test1@test.com) after configuration. Example data packet format:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Csoap:body>\u003Cbr>\u003Csendsharenotificationrequest xmlns=\"urn:zimbraMail\">\u003Cbr>\u003Citem id=\"2\">\u003Cbr>\u003Ce a=\"test1@test.com\">\u003Cbr>\u003Cnotes>\u003C\u002Fnotes>\u003Cbr>\u003C\u002Fe>\u003C\u002Fitem>\u003C\u002Fsendsharenotificationrequest>\u003Cbr>\u003C\u002Fsoap:body>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Mailbox test1@test.com will receive an email to confirm whether to accept folder sharing\u003C\u002Fp>\u003Ch3>2. Code Implementation\u003C\u002Fh3>\u003Ch4>(1) Add File Sharing\u003C\u002Fh4>\u003Cp>Need to specify the target mailbox and shared folder\u003C\u002Fp>\u003Cp>The successful response for adding file sharing returns the zid corresponding to the shared folder\u003C\u002Fp>\u003Cp>Implementation code example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def addshare_request(uri,token):\u003Cbr>    print(\"[*] Input the target mailbox:\")\u003Cbr>    mailbox = input(\"[&gt;]: \")\u003Cbr>    print(\"[*] Input the share folder:\")\u003Cbr>    print(\"    2     Inbox\")\u003Cbr>    print(\"    4     Junk\")\u003Cbr>    print(\"    5     Sent\")\u003Cbr>    print(\"    6     Drafts\")\u003Cbr>\u003Cbr>    folder = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Cbatchrequest xmlns=\"urn:zimbra\" onerror=\"continue\">\u003Cbr>                \u003Cfolderactionrequest xmlns=\"urn:zimbraMail\" requestid=\"0\">\u003Cbr>                \u003Caction op=\"grant\" id=\"{folder}\">\u003Cbr>                \u003Cgrant gt=\"usr\" inh=\"1\" d=\"{mailbox}\" perm=\"rwidx\" pw=\"\">\u003Cbr>                \u003C\u002Fgrant>\u003C\u002Faction>\u003Cbr>                \u003C\u002Ffolderactionrequest>\u003Cbr>            \u003C\u002Fbatchrequest>\u003Cbr>       \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,folder=folder,mailbox=mailbox),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200 and 'zid' in r.text:        \u003Cbr>            pattern_id = re.compile(r\"zid=\\\"(.*?)\\\"\")\u003Cbr>            zid = pattern_id.findall(r.text)[0] \u003Cbr>            print(\"[+] Add success\")\u003Cbr>            print(\"    zid: %s\"%(zid))\u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) Send file sharing request\u003C\u002Fh4>\u003Cp>Requires specifying the target mailbox\u003C\u002Fp>\u003Cp>Code implementation example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def sendsharenotification_request(uri,token):\u003Cbr>    print(\"[*] Input the target mailbox:\")\u003Cbr>    mailbox = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Csendsharenotificationrequest xmlns=\"urn:zimbraMail\">\u003Cbr>            \u003Citem id=\"2\">\u003Cbr>            \u003Ce a=\"{mailbox}\">\u003Cbr>            \u003Cnotes>\u003C\u002Fnotes>\u003Cbr>            \u003C\u002Fe>\u003C\u002Fitem>\u003C\u002Fsendsharenotificationrequest>\u003Cbr>        \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,mailbox=mailbox),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200:   \u003Cbr>            print(\"[+] Send success\")\u003Cbr>        elif r.status_code == 500 and 'no matching grant' in r.text:\u003Cbr>            print(\"[-] You should add share first.\")\u003Cbr>\u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Note: Only after adding a file share can sending a file share request successfully return 200; otherwise, it returns 500 with the message 'invalid request: no matching grant'.\u003C\u002Fp>\u003Ch4>(3) Delete file share\u003C\u002Fh4>\u003Cp>Requires specifying the zid and shared folder corresponding to the target email. The zid can be obtained from the successful response of adding a file share.\u003C\u002Fp>\u003Cp>Example implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>def removeshare_request(uri,token):\u003Cbr>    print(\"[*] Input the zid:\")\u003Cbr>    zid = input(\"[&gt;]: \")\u003Cbr>    print(\"[*] Input the share folder:\")\u003Cbr>    print(\"    2     Inbox\")\u003Cbr>    print(\"    4     Junk\")\u003Cbr>    print(\"    5     Sent\")\u003Cbr>    print(\"    6     Drafts\")\u003Cbr>\u003Cbr>    folder = input(\"[&gt;]: \")\u003Cbr>\u003Cbr>    request_body=\"\"\"\u003Csoap:envelope xmlns:soap=\"http:\u002F\u002Fwww.w3.org\u002F2003\u002F05\u002Fsoap-envelope\">\u003Cbr>        \u003Csoap:header>\u003Cbr>            \u003Ccontext xmlns=\"urn:zimbra\">\u003Cbr>                \u003Cauthtoken>{token}\u003C\u002Fauthtoken>\u003Cbr>            \u003C\u002Fcontext>\u003Cbr>        \u003C\u002Fsoap:header>\u003Cbr>        \u003Csoap:body>\u003Cbr>            \u003Cfolderactionrequest xmlns=\"urn:zimbraMail\">\u003Cbr>            \u003Caction op=\"!grant\" id=\"{folder}\" zid=\"{zid}\">\u003Cbr>            \u003C\u002Faction>\u003C\u002Ffolderactionrequest>\u003Cbr>       \u003C\u002Fsoap:body>\u003Cbr>    \u003C\u002Fsoap:envelope>\u003Cbr>    \"\"\"\u003Cbr>    try:\u003Cbr>        r=requests.post(uri+\"\u002Fservice\u002Fsoap\",headers=headers,data=request_body.format(token=token,folder=folder,zid=zid),verify=False,timeout=15)\u003Cbr>        if r.status_code == 200:        \u003Cbr>            print(\"[+] Send success\") \u003Cbr>        else:\u003Cbr>            print(\"[!]\")\u003Cbr>            print(r.status_code)\u003Cbr>            print(r.text)\u003Cbr>\u003Cbr>    except Exception as e:\u003Cbr>        print(\"[!] Error:%s\"%(e))\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Open Source Code\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>New code has been uploaded to GitHub at the following address:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Add the following five features:\u003C\u002Fp>\u003Cul>\u003Cli>AddShare: Add folder sharing with default permissions rwidx\u003C\u002Fli>\u003Cli>ExportMail: Export emails with search criteria, allowing specification of date and keywords\u003C\u002Fli>\u003Cli>ExportMailAll: Export all emails\u003C\u002Fli>\u003Cli>RemoveShare: Remove folder sharing for the current mailbox\u003C\u002Fli>\u003Cli>SendShareNotification: After adding folder sharing, send a confirmation email to the target mailbox\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article expands the invocation methods of the Zimbra SOAP API, adding five practical features. The implementation methods and ideas can also be tested on XSS vulnerabilities.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",1318,"Onedaysec",7,"published","2026-02-02T08:04:56.384Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Zimbra SOAP API Email Export & Folder Sharing Development Guide","Zimbra SOAP API, email export, folder sharing, development guide, Python, API integration",null,false,[],{"docs":43,"hasNextPage":40},[4,44,45,46],374,373,372,{"title":39,"description":39,"image":39},"2026-07-24T15:37:13.833Z","2026-07-23T16:01:28.523Z","draft","2026-07-23T16:05:43.268Z"]