[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fDuJbouykqdOC3ubk8YrpIDT7rPAh8vALz35x3aGjoFk":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},373,"What optional filters can I apply when exporting emails with Zimbra?","You can add `start` and `end` Unix timestamps to filter by date range, and a `query` parameter to search for keywords (e.g., `content:password`). The time values must be in milliseconds, and the query syntax follows Zimbra’s search tips. This allows targeted export of specific emails, as demonstrated in the [Zimbra SOAP API Development Guide 4 - Email Export and Folder Sharing](\u002Fnews\u002Fzimbra-soap-api-development-guide-4-email-export-and-folder-sharing).","\u003Cp>You can add `start` and `end` Unix timestamps to filter by date range, and a `query` parameter to search for keywords (e.g., `content:password`). The time values must be in milliseconds, and the query syntax follows Zimbra’s search tips. This allows targeted export of specific emails, as demonstrated in the [Zimbra SOAP API Development Guide 4 - Email Export and Folder Sharing](\u002Fnews\u002Fzimbra-soap-api-development-guide-4-email-export-and-folder-sharing).\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>","what-optional-filters-can-i-apply-when-exporting-emails-with-zimbra-1777484047039","email export, filter, query, timestamp, Zimbra search",{"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},[44,45,4,46],375,374,372,{"title":39,"description":39,"image":39},"2026-07-24T15:37:13.833Z","2026-07-23T16:01:28.523Z","draft","2026-07-23T16:05:42.544Z"]