
REST URL for requesting content:

http://server/service/home/[&tilde;][{username}]/[{folder}]?[{query-params}]
       fmt={ics, csv, etc}
       charset={Windows-31J, GBK, etc, default is UTF-8}
       id={item-id}
       imap_id={item-imap-id}
       part={mime-part}
       query={search-query}
       types={types} // when searching
       auth={auth-types}
       start={time}
       end={time}
       sync="1"

          {types}   = comma-separated list.  Legal values are:
                      appointment|chat|contact|conversation|document|
                      message|tag|task|wiki
                      (default is &quot;conversation&quot;)

          {auth-types} = comma-separated list. Legal values are:
                         co     cookie
                         ba     basic auth
                         nsc    do not set a cookie when using basic auth
                         (default is &quot;co,ba&quot;, i.e. check both)

         {time} = (time in milliseconds) |
                  YYYY/dd/mm |
                  mm/dd/YYYY |
                  [-]nnnn{minute,hour,day,week,month,year}  // relative

----------------------

URL for posting to SOAP is:

/service/soap/

-------------------------------

urn:zimbra  -- top-level namespace for global attributes/elements


<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
    <context xmlns="urn:zimbra">
      [<authToken>...</authToken>]
      [<csrfToken>...</csrfToken>]
      [<authTokenControl voidOnExpired="1"/>]
      [<session [id="{returned-from-server-in-last-response}" [seq="{highest_notification_received}"] [type="admin"]/>]
      [<account by="name|id">{account-name-or-id}</account>]
      [<change token="{change-id}" [type="mod|new"]/>]
      [<targetServer>{proxy-target-server-id}</targetServer>]
      [<userAgent name="{client-name}" [version="{client-version}"]/>]
      [<via>{request-ip(user-agent)[,...]}</via>
      [<format type="{response-format}" />]
    </context>
  </soap:Header>
  <soap:Body>
   <FooRequest ... [requestId="{client-generated-id}"]>
   </FooRequest>
  </soap:Body>
</soap:Envelope>

Notification Reliability
   To ensure that the client receives all notifications, the client
must send the highest known notification ID (the highest <notify>
block that the client has received and processed) so that the server
can discard them once it knows they have been received.  If the client
is capable of sending multiple overlapping requests, the client is
responsible for making sure that notifications are not applied more
than once even if they are received more than one time.

Race Conditions

To avoid race conditions, the client may specify the highest change ID
that it knows about in the <change> header element.  The default behavior
(type="mod") will cause mail.MODIFY_CONFLICT to be thrown if we try to
modify an object that has been touched (flags, tags, folders, etc.) since
the specified change ID.  Alternatively, type="new" will throw
mail.MODIFY_CONFLICT if we try to modify an object that has been created
or whose content has been modified since the specified change ID.

In general, the sync client will use type="mod" and the web client will
use type="new".

Proxy Mechanism

The targetServer info is a proxy mechanism to allow a browser client to
send requests to multiple servers.  This is primarily useful for admin
commands, but the mechanism is available for all commands.  Proxying is
needed because some admin commands must be sent to the server being
affected but the browser admin client can only talk to the server it
originally logged on to. (JavaScript security restriction)  If
<targetServer> element is missing, the command is executed on the local
server.  If the target server specified is the local server, the command
is executed locally.  Otherwise, it is proxied.  The server is specified
by id, not by name.

Sessions

The server's default is disabling sessions for every SOAP request.
Clients that desire notification must explicitly request that the server
maintain a session for them.  This is done by specifying a <session/>
element in the request.

When sessions are explicitly requested by the client, the server
will return the client's active session ID in the response's <session/>
header element.  If this session ID is different from the one sent by the
client (or if the client requested a new session by including just a bare
"<session/>" in the header), the client should assume the old session
(if any) has expired and immediately start using the returned session ID.

If a new session is created (due to no session ID being supplied in the request
or the old session timing out), the response context header will contain a
<refresh> block containing the current set of tags and folders.  If there
have been any changes to the mailbox since the last soap operation (including
changes made due to this operation), there will also be a <notify> block in
the response context containing information on the deleted, created, and
modified items in the mailbox.  (Note that a session will not return any
notifications if <nonotify/> was ever specified in a <context> request
element involving the session.)  If there is a session, there will be a
<change> element specifying the last change ID on the server.

  - deleted has just id
  - created has full ToXML item dump
  - modified has type/id, modified fields

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  [<soap:Header>
     <context xmlns="urn:zimbra">
       <session id="{session-id}" [type="admin"]/>
       <change token="{change-id}"/>
       [<refresh>
          <version>{server-version-string}</version>
          <mbx s="{bytes-used}" [acct="{remote-mailbox-owner-id}"]/>
          <tags>
            <-- all tags listed -->
          </tags>
          <folder id="1">
            <folder .../>
            <folder ...>
              <folder .../>
            </folder>
            <folder .../>
          </folder>
        </refresh>]
       [<notify seq="sequence-number">
          <deleted id="665,1192,452,883"/>
          <created>
            <tag id="466" name="phlox" u="8" n="13"/>
            <folder id="4353" name="a&p" u="2" l="1"/>
            <folder id="4356" name="subfolder" u="2" l="4353"/>
            <link id="1" name="new-mount-point" l="1" n="6" u="1" f="u" owner="user1@example.com" zid="151bd192-e19a-40be-b8c9-259b21ffac48" rid="2" oname="user1folder">
              <folder id="151bd192-e19a-40be-b8c9-259b21ffac48:260" name="remote-subfolder" n="43" l="151bd192-e19a-40be-b8c9-259b21ffac48:2"/>
            </link>
          </created>
          <modified>
            <tag id="652" u="0" n="2"/>
            <m id="553" f="ua"/>
          </modified>
        </notify>]+
     </context>
   <soap:/Header>]
  <soap:Body>
   <FooResponse ... [requestId="{client-generated-id}"]>
   </FooResponse>
  </soap:Body>
</soap:Envelope>



NOTES: The requestId="..." attribute is optional in the request body. If present, the server will
       include it in the response body element.

batch requests:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
    <context xmlns="urn:zimbra">
       <authToken>...</authToken>
       [<session [id="{returned-from-server-in-last-response}"]/>]
       [<account by="name|id">{account-name-or-id}</account>]
       [<change token="{change-id}" [type="mod|new"]/>]
    </context>
  </soap:Header>
 <soap:Body>
  <BatchRequest xmlns="urn:zimbra" onerror="continue*|stop">
    <FooRequest requestId="1">
    </FooRequest>
    <BarRequest requestId="2">
    </BarRequest>
  </BatchRequest>
 </soap:Body>
</soap:Envelope>

response:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  [<soap:Header>
     <context xmlns="urn:zimbra">
       <session id="{session-id}" [type="admin"]>
       [<refresh>
          <mbx s="{bytes-used}" [acct="{remote-mailbox-owner-id}"]/>
          <tags>
            <-- all tags listed -->
          </tags>
          <folder id="1">
            <folder .../>
            <folder ...>
              <folder .../>
            </folder>
            <folder .../>
          </folder>
        </refresh>]
       [<notify seq="sequence-number">
          <deleted ids="665,466,452,883"/>
          <created>
            <tag id="966" name="phlox" u="8" n="12"/>
            <folder id="4353" name="a&p" u="2" l="1"/>
          </created>
          <modified>
            <tag id="654" u="0" n="3"/>
            <m id="553" f="ua"/>
          </modified>
        </notify>]+
     </context>
   <soap:/Header>]
 <soap:Body>
  <BatchResponse xmlns="urn:zimbra">
    <soap:Fault requestId="1">
    </soap:Fault>
    <BarResponse ... requestId="2">
    </BarResponse>
  </BatchResponse>
 </soap:Body>
</soap:Envelope>

User Agent

userAgent is an optional context element that is used for identifying the
type of SOAP client that's making the request.  The user agent is written
to mailbox.log messages with the context string "ua".

Request and Response Formats

The requests and responses can be specified in XML or JSON format. The
server determines the request format automatically but JSON requests
MUST follow these requirements:

* request encoded in UTF-8
* start with '{' for server to identify JSON content
* do not include "Envelope" object
* elements specified as "name": { ... }
* attributes specified as "name": "value"
* namespace attribute specified as "_jsns": "ns-uri"
* element text content specified as "_content": "content"
* element list specified as "name": [ ... ]

Example:

  {
    "Header": {
      "context": {
        "_jsns": "urn:zimbra",
        "authToken": {
          "_content": "0_3e761bdc...303b"
        }
      }
    },
    "Body": {
      "FooRequest": {
        "_jsns": "urn:zimbra",
        "name": "attribute content",
        "_content": "element content"
      }
    }
  }

The response format is the same as the request format by default.
To change, specify a "format" element in the request's Header element
with a "type" attribute. The value must be either "xml" or "js".

SOAP request with JSON response:

  <soap:Envelope ...>
    <soap:Header>
      <context xmlns="urn:zimbra">
        ...
        <format type='js' />
      </context>
    </soap:Header>
    ...
  </soap:Envelope>

JSON request with XML response:

  {
    "Header": {
      "context": {
        ...
        "format": { "type": "xml" },
        "_jsns": "urn:zimbra"
      }
    },
     ...
  }

Names of all MailItem types have the following requirements:

* No longer than 255 characters.
* Cannot contain ':', '/', '"', '\t', '\r', '\n'.
* Cannot be "." or "..".
* Cannot be null or empty.

In addition, the server removes trailing whitespace and characters below 0x20 from item names.

-----------------------------

SOAP 1.2

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
 <soap:Body>
  <soap:Fault>
    <soap:Code>
       <soap:Value>soap:Sender</soap:Value>
    </soap:Code>
    <soap:Reason><soap:Text>...</soap:Text><soap:Reason>
    <soap:Detail>
      <Error xmlns="urn:zimbra">
        <Code>...</Code>
        [<a n="{name}" t="{type}">{value}</a>]* // error information (arguments, e.g. ID that was bad, or whatever)
      </Error>
    </soap:Detail>
  </soap:Fault>
 </soap:Body>
</soap:Envelope>

SOAP 1.1

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <soap:Fault>
   <soap:faultcode>soap:Server</soap:faultcode>
   <soap:faultstring>Server Error</soap:faultstring>
   <soap:detail>
     <Error xmlns="urn:zimbra">
        <Code>...</Code>
        [<a n="{name}" t="{type}">{value}</a>]* // error information (arguments, e.g. ID that was bad, or whatever)
      </Error>
    </soap:detail>
  </soap:Fault>
 </soap:Body>
</soapEnvelope>

global soap/system errors used with zimbra:Error/Code:

 service.FAILURE          - generic system failure
 service.INVALID_REQUEST  - bad request (missing args, etc)
 service.UNKNOWN_DOCUMENT - no handler for specified document
 service.PARSE_ERROR      - XML parsing error
 service.PERM_DENIED      - permission denied
 service.AUTH_REQUIRED    - an authtoken is required
 service.AUTH_EXPIRED     - authentication creds have expired
 service.WRONG_HOST       - operation is sent to a wrong host
 service.PROXY_ERROR      - unable to proxy operation
 service.TOO_MANY_HOPS    - operation was proxied too many times
 service.INTERRUPTED      - index operation was interrupted
 service.NOT_IN_PROGRESS  - attempt to stop index operation when it was not in progress
 service.ALREADY_IN_PROGRESS     - attempt to start index operation when it was already in progress
 service.NO_SPELL_CHECK_URL      - spellcheck is not available
 service.RESOURCE_UNREACHABLE    - unable to reach the remote resource
 service.TEMPORARILY_UNAVAILABLE - resource is temporarily unavailable
 service.NON_READONLY_OPERATION_DENIED -

-----------------------------
 urn:zimbraAccount

 account error/codes: (includes service.*):

   account.AUTH_FAILED          - bad account/password
   account.CHANGE_PASSWORD      - password must be changed
   account.PASSWORD_LOCKED      - password can't be changed
   account.PASSWORD_CHANGE_TOO_SOON = password can't be changed yet
   account.PASSWORD_RECENTLY_USED = can't use the same password again
   account.INVALID_PASSWORD     - new password does not meet the system's rules (length, content, etc.)
   account.INVALID_ATTR_NAME    - the specified attribute name is invalid
   account.INVALID_ATTR_VALUE   - the specified attribute value is invalid
   account.MULTIPLE_ACCOUNTS_MATCHED - when auth by foreignPrincipal matches multiple accounts with the same foreignPrincipal
   account.NO_SUCH_ACCOUNT
   account.NO_SUCH_ALIAS
   account.NO_SUCH_DOMAIN
   account.NO_SUCH_COS
   account.NO_SUCH_IDENTITY
   account.NO_SUCH_SIGNATURE
   account.NO_SUCH_DATA_SOURCE
   account.NO_SUCH_SERVER
   account.NO_SUCH_ZIMLET
   account.NO_SUCH_DISTRIBUTION_LIST
   account.NO_SUCH_CALENDAR_RESOURCE
   account.NO_SUCH_MEMBER
   account.MEMBER_EXISTS
   account.ACCOUNT_EXISTS
   account.DOMAIN_EXISTS
   account.COS_EXISTS
   account.SERVER_EXISTS
   account.DISTRIBUTION_LIST_EXISTS
   account.IDENTITY_EXISTS
   account.SIGNATURE_EXISTS
   account.DATA_SOURCE_EXISTS
   account.DOMAIN_NOT_EMPTY
   account.MAINTENANCE_MODE
   account.ACCOUNT_INACTIVE
   account.TOO_MANY_ACCOUNTS
   account.TOO_MANY_IDENTITIES
   account.TOO_MANY_SIGNATURES
   account.TOO_MANY_DATA_SOURCES
   account.TOO_MANY_SEARCH_RESULTS
   account.TWO_FACTOR_AUTH_FAILED
   account.TWO_FACTOR_SETUP_REQUIRED


 <AuthRequest xmlns="urn:zimbraAccount" [persistAuthTokenCookie="1"][csrfTokenSecured="0|1"] [deviceTrusted="0|1"] [generateDeviceId="0|1"][tokenType="JWT"]>
   [<account by="name|id|foreignPrincipal">...</account>]
   [<password>...</password>]
   [<recoveryCode>...</recoveryCode>]
   [<preauth timestamp="{timestamp}" expires="{expires}">{computed-preauth-value}</preauth>]
   [<authToken [verifyAccount="1"]>...</authToken>]
   [<jwtToken>...</jwtToken>]
   [<virtualHost>{virtual-host}</virtualHost>]
   [<prefs>[<pref name="..."/>...]</prefs>]
   [<attrs>[<attr name="..."/>...]</attrs>]
   [<twoFactorCode>...</twoFactorCode>]
   [<requestedSkin>{skin}</requestedSkin>]
   [<trustedToken>...</trustedToken>]
   [<deviceId>...</deviceId>]
 </AuthRequest>

 <AuthResponse>
   <authToken>...</authToken>
   [<csrfToken>...</csrfToken>]
   <lifetime>{lifetime-in-millseconds}</lifetime>
   <session .../>
   <refer>{mail-host}</refer>
   [<prefs><pref name="{name}" modified="{modified-time}">{value}</pref>...</prefs>]
   [<attrs><attr name="{name}">{value}</attr>...</attrs>]
   [<skin>{skin-name}</skin>]
   [<trustedToken>...</trustedToken>]
   [<trustLifetime>...</trustLifetime>]
   [<deviceId>...</deviceId>]
   [<twoFactorAuthRequired>...</twoFactorAuthRequired>]
   [<trustedDevicesEnabled>...</trustedDevicesEnabled>]
 </AuthResponse>

Note:
when tokenType is set as "JWT", token returned in response is a JWT(JasonWebToken).

when specifiying an account, one of <password>, <preauth> or <recoveryCode> must be specified. see preauth.txt for a discussion of preauth.
recoveryCode can be used for auth during password reset flow.

An authToken can be passed instead of account/password/preauth to validate an existing auth token.
If verifyAccount="1", <account> is required and the account in the auth token is compared to the named account.
Mismatch results in auth failure.  An external app that relies on ZCS for user identification can use this to
test if the auth token provided by the user belongs to that user.
If verifyAccount="0" (default), only the auth token is verified and any <account> element specified is ignored.

JWT can also be passed instead of account/password/preauth to validate an existing JWT.when JWT is passed,
 ZM_JWT cookie should be set in the request or jwtSalt should be present in the soap context.
When token type is JWT, authToken element is not supported i.e. JWT can not be issued on the basis of an auth token.

  {persistAuthTokenCookie} = controls whether the auth token cookie in the response should 
                             be persisted when the browser exits.
                             0: (default)
                                the cookie will be deleted when the Web browser exits.
                             1: The "Expires" attribute of the cookie will be set per rfc6265.
                  
  
  {csrfTokenSecured} = controls whether the client has the capability to handle CSRF token
                0: (default) the client is not capable of handling CSRF token
                1: The client is capable of handling CSRF token.
  {mail-host} = host additional SOAP requests should be directed to. Always returned, might be same as original host request was sent to.

  {virtual-host} = if specified (in conjunction with by="name"), virtual-host is used to determine the domain of the account name, if it
                   does not include a domain component. For example, if the domain foo.com has a zimbraVirtualHostname of "mail.foo.com",
                   and an auth request comes in for "joe" with a virtualHost of "mail.foo.com", then the request will be equivalent to
                   logging in with "joe@foo.com".

  only attrs that are allowed to be returned by GetInfo will be returned by this call

  {requested-skin} = if specified the name of the skin requested by client

  {skin-name} = if requested-skin specified, the name of the skin to use
  
  {trusted} = if trusted=1, the requesting client will not require two-factor authentication in the future

  {generateDeviceId} = if 1, the server will generate a unique ID for the client, and return it in the deviceId element.

Additional Notes about Auth behavior when mailstore is accessed via reverse proxy (i.e. nginx)

1. All mail stores are capable of validating the user and generating an Auth Token. Nginx will direct the auth request to an arbitrary server based on round robin balancing.

2. When a session context is requested, AuthRequest will only return a session context if the request was passed to the mail store that holds the user account being accessed.
Any other mail store will validate the user, and generate an Auth Token, BUT will not return a session context.

3. For single node configurations (with no nginx proxy) - the session ID can be passed in either manner - as a cookie -or- in the Soap Header. For code portability it is best to use the cookie method.  

4. For a multi-node configuration passing the Auth Token in the SOAP Header of subsequent SOAP requests will NOT allow nginx to direct those requests to the correct mail store for the user account.
The Auth Token MUST instead be sent as a cookie "ZM_AUTH_TOKEN=...Auth Token returned from AuthRequest..." as this is how nginx tells which mail store the request needs to be sent to.

See also //depot/zimbra/main/ThirdParty/nginx/docs/HTTP for more details on the semantics of auth and nginx.

See ZimbraTwoFactorAuth server extension docs for more details on two-factor authentication-related request/response attributes.
 
---------

 <ChangePasswordRequest>
   <account by="name">...</account>
   <oldPassword>...</oldPassword>
   <password>...</password>
   [<virtualHost>{virtual-host}</virtualHost>]
 </ChangePasswordRequest>

<ChangePasswordResponse>
   <authToken>...</authToken>
   <lifetime>...</lifetime>
<ChangePasswordResponse/>

   {virtual-host} = if specified virtual-host is used to determine the domain of the account name, if it
                   does not include a domain component. For example, if the domain foo.com has a zimbraVirtualHostname of "mail.foo.com",
                   and an auth request comes in for "joe" with a virtualHost of "mail.foo.com", then the request will be equivalent to
                   logging in with "joe@foo.com".

  Returns new authToken, as old authToken will be invalidated on password change.

---------------------------
<EndSessionRequest xmlns="urn:zimbraAccount" [logoff="1"] [all="1"] [excludeCurrent="1"] [sessionId="session_id"]/>

Ends the current session, removing it from all caches.  Called when
the browser app (or other session-using app) shuts down.  Has no
effect if called in a <nosession> context.

Setting logoff to "1" will prevent the cookie from being re-used.
Setting sessionId will end session for given session id and not current session.

When all is 1, all web sessions of the user will be cleared.
When all is 1 and excludeCurrent is also 1, all web sessions of the user, except the current session will be cleared.
For all and sessionId, <nosession> context has no effect.

---------
 <GetPrefsRequest>
   <!-- get only the specified prefs -->
   [<pref name="{name1}"/>
    <pref name="{name2}"/>]
 </GetPrefsRequest>

 If no <pref> elements are provided, all known prefs are returned in the response.
 If <pref> elements are provided, only those prefs are returned in the response.

<GetPrefsResponse>
   <pref name="{name}">{value}</pref>
   ...
   <pref name="{name}">{value}</pref>
 </GetPrefsResponse>

----------------------------

<GetInfoRequest [sections="mbox,prefs,attrs,zimlets,props,idents,sigs,dsrcs,children"] [rights="{comma-separated-rights}"]>
</GetInfoRequest>

   <-- by default, GetInfo returns all data; to limit the returned data, specify only the sections you want in the "sections" attr -->

<GetInfoResponse>
   <version>{version}</version>
   <id>{account-id}</id>
   <profileImageId>{profile-image-id}</profileImageId>
   <name>{account-name}</name>
   <lifetime>...</lifetime>
   [<adminDelegated>{admin-delegated}</adminDelegated>
    <rest>{account-base-REST-url}</rest>
    <used>{used}</used>
    <prevSession>{previous-SOAP-session}</prevSession>
    <accessed>{last-SOAP-access}</accessed>
    <recent>{recent-messages}</recent>
   ]
   <docSizeLimit>{document-size-limit}</docSizeLimit>
   <attSizeLimit>{attachment-size-limit}</attSizeLimit>
   <cos name="cos-name" id="cos-id"/>
   <attrs>
    <attr name="{name}">{value}</a>
     ...
    <attr name="{name}">{value}</a>
   </attrs>
   <prefs>
     <pref name="{name}">{value}</pref>
     ...
     <pref name="{name}">{value}</pref>
   </prefs>
   <props>
     <prop zimlet="{zimlet-name}" name="{name}">{value}</prop>
     ...
     <prop zimlet="{zimlet-name}" name="{name}">{value}</prop>
   </props>
   <zimlets>
     <zimlet>
       <zimletContext baseUrl="..." priority="..." presence="{zimlet-presence}"/>
       <zimlet>...</zimlet>
       <zimletConfig>...</zimletConfig>
     </zimlet>
     ...
   </zimlets>
   <mailURL>{mail-url}</mailURL>+
   <publicURL>{account-base-public-url}</publicURL>
   [<adminURL>{admin-base-public-url}</adminURL>]
   [<communityURL>{community-url}</communityURL>]
   [<boshURL>{bosh-url}</boshURL>]
   <identities>
     <identity name={identity-name} id="...">
       <a name="{name}">{value}</a>
       ...
       <a name="{name}">{value}</a>
     </identity>*
   </identities>
   <signatures>
     <signature name={signature-name} id="...">
       <a name="{name}">{value}</a>
       ...
       <a name="{name}">{value}</a>
     </signature>*
   </signatures>
   <dataSources>
     {data-source}
     ...
   </dataSources>*
   <childAccounts>
     <childAccount name="{child-account-name}" visible="0|1" id="{child-account-id}">
         <attrs>
            <attr name="{name}">{value}</a>*
         </attrs>
     </childAccount>*
   </childAccounts>
   [<rights>
      {same as DiscoverRightsResponse}
    </rights>]
</GetInfoResponse>

  {version} = server version: <major>[.<minor>[.<maintenance>]][build] <release> <date>[ <type>]
  {account-name} = email address (user@domain)
  {life-time} = number of milliseconds until auth token expires
  {admin-delegated} = "1" if the auth token is a delegated auth token issued to an admin account
  {account-base-REST-url} = base REST URL for the requested account


  returned only if the command successfully executes on the target user's home mail server:
    {used} = mailbox quota used in bytes
    {last-SOAP-access} = time (in millis) of last write op from this session, or from *any* SOAP session if we don't have one
    {previous-SOAP-session} = time (in millis) of last write op from any SOAP session before this session was initiated,
                              or same as {last-SOAP-access} if we don't have one
    {recent-messages} = number of messages received since the previous soap session, or since the last SOAP write op if we don't have a session

  prefs = user-settable preferences
  attrs = account attrs that aren't user-settable, but the front-end needs.
          Only attributes listed in zimbraAccountClientAttrs will be returned.

  {mail-url} = URL to talk to for soap service for this account. i.e:

       http://server:7070/service/soap/

       Multiple URLs can be returned if both http and https (SSL) are enabled. If only one of the two is enabled,
       the only one URL will be returned.

  {account-base-public-url} = base public URL for the requested account

  {admin-base-public-url} = base admin console URL. Only returned for admin accounts.

  attrs under <childAccount>: including the following attrs of the child account:
        - displayName

  {data-source}: see GetDataSourcesRequest for details

  {zimlet-presence}: mandatory | enabled | disabled

----------------------------

<GetAccountInfoRequest>
  <account by="id|name">...</account>
</GetAccountInfoRequest>

  Note: For historical reasons, there are some minor differences between the Admin and Account versions of
        GetAccountInfoResponse.

<GetAccountInfoResponse>
   <name>{account-name}</name>
   <attr name="{name}">{value}</a>+
   <soapURL>{soap-url}</soapURL>+
   <publicURL>{account-base-public-url}</publicURL>
   [<adminURL>{admin-base-public-url}</adminURL>]
   [<changePasswordURL>{change-password-url}</changePasswordURL>]
   [<communityURL>{community-url}</communityURL>]
   [<boshURL>{bosh-url}</boshURL>]
</GetAccountInfoResponse>

  {account-name} = email address (user@domain)

  attr = account attrs. Currently only these attrs are returned:

      zimbraId       - the unique UUID of the zimbra account
      zimbraMailHost - the server on which this user's mail resides
      displayName    - Display name for the account

  {soap-url} = URL to talk to for soap service for this account. i.e:

       http://server:7070/service/soap/

       Multiple URLs can be returned if both http and https (SSL) are enabled. If only one of the two is enabled,
       the only one URL will be returned.

  {account-base-public-url} = base public URL for the requested account
  {admin-base-public-url} = base admin console URL. Only returned for admin accounts.
  {change-password-url} = URL to talk to in order to change a password.  Not returned if not configured via domain
                          attribute zimbraChangePasswordURL
  {community-url} = Zimbra Community URL to load in Community tab. 
                    The URL points to /api.ashx/v2/oauth/redirect script in Zimbra Community and contains signed GET parameters used by Zimbra Community to authenticate current user.  
                    This parameter is returned only when zimbraFeatureSocialExternalEnabled is set to TRUE and the following attributes are configured:
                        zimbraCommunityAPIClientID, zimbraCommunityAPIClientSecret, zimbraCommunityUsernameMapping,zimbraCommunityBaseURL,zimbraCommunityHomeURL  
  {bosh-url} = Proxy URL for accessing XMPP over BOSH. Should be returned only when zimbraFeatureChatEnabled is set to TRUE for Account/COS
----------------------------

<GetAvailableSkinsRequest/>

<GetAvailableSkinsResponse>
  <skin name="{skin-name}"/>+
</GetAvailableSkinsResponse>

Returns intersection of installed skins on the server and the list
specified in the zimbraAvailableSkin on an account (or its
CoS).  If none is set in zimbraAvailableSkin, it returns the
entire list of installed skins.  The installed skin list is obtained
by a directory scan of the designated location of skins on a server.

----------------------------

<GetAvailableCsvFormatsRequest/>

<GetAvailableCsvFormatsResponse>
  <csv name="{format-name}"/>+
</GetAvailableCsvFormatsResponse>

Returns the known CSV formats that can be used for
import and export of addressbook.

----------------------------


 <SearchGalRequest [type="{type}"] [limit="..."] [offset="..."] [sortBy="{sort-by}"] [groupBy="{group-by}"]  
     [needExp="1|0"] [needIsOwner="[1|0]"] [needIsMember="[all|directOnly|none]"]>
  [<cursor id="{prevId}" sortVal="{prevSortValue}" endSortVal="{endSortValue}"/> ]
   <name>...</name>

   [<searchFilter>
     <conds [not="1|0"] [or="1|0"] >
       [<cond> or <conds>]+
     </conds>  (exactly one instance of <conds>)

     -- or --

     <cond [not="1|0"] attr="{attr}" op="{op}" value="{value}" />  (exactly one instance of <cond>)
   </searchFilter>]

 </SearchGalRequest>

 <SearchGalResponse more="{more}" sortBy="sort-by" offset="..." [tokenizeKey="{tokenize-key-op}"] [paginationSupported="1|0"]>
   <cn [exp="1|0"] [isOwner="1|0"] [isMember="1|0"] ref="{gal-entry-ref}">
     <a n="...">...</a>+
   </cn>*
 </SearchGalResponse>

  {more-flag} = 1 if the results were truncated.

  {tokenize-key-op} = and|or
         - Not present if the search key was not tokenized.
         - Some clients backtrack on GAL results assuming the results of a more
           specific key is the subset of a more generic key, and it checks cached
           results instead of issuing another SOAP request to the server.
           If search key was tokenized and expanded with AND or OR, this cannot
           be assumed.

  {type} = type of addresses to search
           "account" for regular user accounts, aliases and distribution lists
           "resource" for calendar resources
           "all" for combination of both types
           if omitted, defaults to "all"

  needExp: if the "exp" flag is needed in the response for group entries.
           default is 0
           
  needIsOwner: if the "isOwner" flag is needed in the response for group entries.
               default is 0   
           
  needIsMember = if the "isMember" flag is needed in the response for group entries.
                 all: the isMember flag returned is 1 if the user is a direct or indirect 
                      member of the group, 0 otherwise.
                 directOnly: the isMember flag returned is 1 if the user is a direct 
                             member of the group, 0 otherwise.
                 none(default): the isMember flag is not returned

  {gal-entry-ref}: a unigue reference id for the GAL entry.  This is the ref id to be used for the value
                   of type="G" contact group members.  See CreateContactRequest and ModifyContactRequest.


  paginationSupported:
     1 - limit and offset in the request was honored
     0 - the underlying search does not support pagination
         limit and offset in the request was not honored
         
  exp: if the user can (has right to) expand group members
       returned only if needExp is 1 in the request and only on group entries (type=group in attrs on a <cn>).

  isOwner: whether the user is an owner of the group
           returned only if needIsOwner is 1 in the request and only on group entries (type=group in attrs on a <cn>).
           
  isMember: whether the user is a member of the group
            returned only if needIsMember is 1 in the request and only on group entries (type=group in attrs on a <cn>).

  see SearchRequest for use of cursor.

  see SearchCalendarResources for use of searchFilter

----------------------------

 <AutoCompleteGalRequest [type="{type}"] [needExp="1|0"]>
   <name>...</name>
 </AutoCompleteGalRequest>

 <AutoCompleteGalResponse more="{more}"  [tokenizeKey="{tokenize-key-op}"]>
   <cn [exp="1|0"]>
     <a n="...">...</a>+
   </cn>*
 </AutoCompleteGalResponse>

  - the number of entries in the response is limited by Account/COS attribute
    zimbraContactAutoCompleteMaxResults with default value of 20.

  {type} = type of addresses to auto-complete on
           "account" for regular user accounts, aliases and distribution lists
           "resource" for calendar resources
           "group" for contact groups
           "all" for combination of all types
           if omitted, defaults to "account"

  {more-flag} = 1 if the results were truncated.

  {tokenize-key-op} = and|or
         - Not present if the search key was not tokenized.
         - Some clients backtrack on GAL results assuming the results of a more
           specific key is the subset of a more generic key, and it checks cached
           results instead of issuing another SOAP request to the server.
           If search key was tokenized and expanded with AND or OR, this cannot
           be assumed.

  needExp: if the "exp" flag is needed in the response for group entries.
           default is 0

  exp: if the user can (has right to) expand group members
       returned only if needExp is 1 in the request and only on group entries (type=group in attrs on a <cn>).

----------------------------

<AutoCompleteRequest [folders="{folders}"] [includeGal="0|1"] [needExp="1|0"] [t="{type}"]>
  <name>...</name>
</AutoCompleteRequest>

<AutoCompleteResponse canBeCached="0|1">
  <match ranking="..." email="..." type="gal|contact|rankingTable" isGroup="1|0" [exp="1|0"] [display="..."] [id="..."] [l="..."] [first="..."] [middle="..."] [last="..."] [nick="..."] [full="..."] [company="..."] [fileas="..."] />*
</AutoCompleteResponse>

  {folders} - comma separates list of folder IDs.

  {type} = type of addresses to auto-complete on
           "account" for regular user accounts, aliases and distribution lists
           "resource" for calendar resources
           "group" for contact groups
           "all" for combination of all types
           if omitted, defaults to "account"

  - the number of entries in the response is limited by Account/COS attribute
    zimbraContactAutoCompleteMaxResults with default value of 20.
  - email field contains comma separated email addresses in case of group
  - display field contains string that should be displayed by the client
  - isGroup: if the entry is a group
  - needExp: if the "exp" flag is needed in the response for group entries.
             default is 0
  - exp: if the user can (has right to) expand group members
         returned only if needExp is 1 in the request and only on group entries (isGroup=1).

----------------------------

 <SyncGalRequest [limit={limit}] [token="{previous-token}] [idOnly={true|false}] [getCount={true|false}]"/>

  {limit} - Page size control for SyncGalRequest. The maximum entries that can be returned for
 every SyncGal Request can be controlled by specifying this limit.
  {previous-token} - The page offset token from where sync gal should be resumed.

 <SyncGalResponse token="{new-token}" [galDefinitionLastModified="{timestamp}"] [throttled="{throttled-flag}"]
                                     [fullSyncRecommended="{fullSyncRecommended-flag}"] [remain="{count of remaining items}"]>
   <cn>...</cn>*
   <deleted id="{itemId}">*
 </SyncGalResponse>

  If the request has idOnly set to true, then the response will contain
  id attribute without all the contact fields populated.  The sync client
  then should make batch request to the server to fetch the contact fields
  with <GetContactsRequest/>.
  If the request has getCount set to true, then the response will contain count of items remaining.
  Note: idOnly only works when GAL sync account is configured/enabled.
  If idOnly is specified and GAL sync account is not enabled, idOnly will
  be ignored.
  Note: getCount works only when idOnly is set to true and GAL sync account is configured/enabled.
  galDefinitionLastModified is the time at which the GAL definition is last modified.
  This is returned if the sync does not happen using GAL sync account.
  {throttled-flag} - true if the SyncGal request is throttled.
  {fullSyncRecommended-flag} - true if GalSync Account is available and the client is using LDAP based sync.

----------------------------

 <SearchCalendarResourcesRequest>
     [attrs="a1,a2,a3"] [sortBy="{sortBy}"] [sortAscending="{sortAscending}"] [limit="..."] [offset="..."]>

   [<name>...</name>]
   <searchFilter>
     <conds [not="1|0"] [or="1|0"] >
       [<cond> or <conds>]+
     </conds>  (exactly one instance of <conds>)

     -- or --

     <cond [not="1|0"] attr="{attr}" op="{op}" value="{value}" />  (exactly one instance of <cond>)
   </searchFilter>

 </SearchCalendarResourcesRequest>

 <SearchCalendarResourcesResponse [paginationSupported="1|0"]>
   <calresource name="{name}" id="{id}">
     <a n="...">...</a>+
   </calresource>*
 </SearchCalendarResourcesResponse>

 Notes:
   SearchCalendarResourcesRequest:
   attrs - comma-separated list of attrs to return ("displayName", "zimbraId", "zimbraCalResType")
   sortBy - name of attribute to sort on. default is the calendar resource name.
   sortAscending - whether to sort in ascending order (0/1), 1 is default

   name: if specified, pass through to the GAL search as the search key

   must have exactly one <conds> child or exactly one <cond> child and no other child element

   conds: denotes a compound condition
     must have 1 or more children
     each child can be a <cond> or <conds>
     not - if 1, negate the compound condition
     or - if 1, child conditions are OR'd together; if 0 (default), they are AND'ed together

   cond: denotes a simple condition of "attr operator value" form
     not - if 1, negate the condition
     attr - attribute name
     op - operator; valid operators are:
          "eq" - attr equals value (integer or string)
          "has" - attr has value (substring search)
          "ge" - attr greater than or equal to integer value
          "le" - attr less than or equal to integer value
          "gt" - attr greater than (but not equal to) integer value
          "lt" - attr less than (but not equal to) integer value
          "startswith" - attr starts with value (string)
          "endswith" - attr ends with value (string)
     value - value

   SearchCalendarResourcesResponse:
   paginationSupported:
     1 - limit and offset in the request was honored
     0 - the underlying search does not support pagination
         limit and offset in the request was not honored


----------------------------

 <ModifyPrefsRequest>
   [<pref name="{name}">{value}</pref>...]+
 </ModifyPrefsRequest>

 <ModifyPrefsResponse/>

 Notes:
   For multi-value prefs, just add the same attribute with 'n' different values:
      <ModifyPrefsRequest>
          <pref name="foo">value1</pref>
          <pref name="foo">value2</pref>
          .
          .
          .
      </ModifyPrefsRequest>

   You can also add/subtract single values to/from a multi-value pref by prefixing
   the preference name with a '+' or '-', respectively in the same way you do when
   using zmprov. For example:
      <ModifyPrefsRequest>
          <pref name="+foo">value1</pref>
          <pref name="-foo">value2</pref>
          .
          .
          .
      </ModifyPrefsRequest>


The JSON version is different:
    {
        ModifyPrefsRequest: {
            "_attrs": {
                "prefName1": "prefValue1",
                "prefName2": "prefValue2"
                "+nameOfMulitValuedPref3": "addedPrefValue3",
                "-nameOfMulitValuedPref4": "removedPrefValue4",
                "nameOfMulitValuedPref5": ["prefValue5one","prefValue5two"],
                ...
            },
            _jsns: "urn:zimbraAccount"
        }
    }

For adding an profile image, you need to upload the image first and provide the upload id (aid) as value in 'zimbraPrefAccountProfileImage' pref name.

---------

<CreateIdentityRequest>
  <identity name="{identity-name}">
    <a name="{name}">{value}</a>
    ...
    <a name="{name}">{value}</a>
  </identity>
</CreateIdentityRequest>

<CreateIdentityResponse>
  <identity name="{identity-name}" id="{identity-id}">
   ....
  </identity>
</CreateIdentityResponse>


Allowed attributes (see objectclass zimbraIdentity in zimbra.schema)

  zimbraPrefBccAddress
    zimbraPrefForwardIncludeOriginalText
    zimbraPrefForwardReplyFormat
    zimbraPrefForwardReplyPrefixChar
    zimbraPrefFromAddress
    zimbraPrefFromDisplay
  zimbraPrefMailSignature
    zimbraPrefMailSignatureEnabled
    zimbraPrefMailSignatureStyle
    zimbraPrefReplyIncludeOriginalText
    zimbraPrefReplyToAddress
    zimbraPrefReplyToDisplay
    zimbraPrefReplyToEnabled
    zimbraPrefSaveToSent
    zimbraPrefSentMailFolder
    zimbraPrefUseDefaultIdentitySettings
    zimbraPrefWhenInFolderIds
    zimbraPrefWhenInFoldersEnabled
    zimbraPrefWhenSentToAddresses
    zimbraPrefWhenSentToEnabled


---------

<GetIdentitiesRequest/>

<GetIdentitiesResponse>
  <identity name="{identity-name}" id="{identity-id}">
    <a name="{name}">{value}</a>
    ...
    <a name="{name}">{value}</a>
  </identity>+
</GetIdentitiesResponse>

---------

<ModifyIdentityRequest>
  <identity [name="{identity-name}" | id="{identity-id}"]>
    <a name="{name}">{value}</a>
    ...
    <a name="{name}">{value}</a>
  </identity>
</ModifyIdentityRequest>

<ModifyIdentityResponse/>

<-- must specify either 'name' or 'id' -->

---------

<DeleteIdentityRequest>
  <identity [name="{identity-name}" | id="{identity-id}"]/>
</DeleteIdentityRequest>

<DeleteIdentityResponse/>

<-- must specify either 'name' or 'id' -->

---------

<CreateSignatureRequest>
  <signature name="{signature-name}" [id="{id}"]/>
    <content type="{text/plain | text/html}">{signature-value}</content>+
    [<cid>{contact-id}</cid>]
  </signature>
</CreateSignatureRequest>

<CreateSignatureResponse>
  <signature id="{id}" name="{signature-name}"/>
</CreateSignatureResponse>

- If an id is provided it will be honored as the id for the signature.

- CreateSignature will set account default signature to the signature being created
  if there is currently no default signature for the account.

- There can be at most one text/plain signatue and one text/html signature.

- {contact-id} contact id associated with this signature

---------

<GetSignaturesRequest/>

<GetSignaturesResponse>
  <signature name="{signature-name}" id="{signature-id}"
    <content type="{text/plain | text/html}">{signature-value}</content>+
    [<cid>{contact-id}</cid>]
  </signature>+
</GetSignaturesResponse>

---------

<ModifySignatureRequest>
  <signature id="{signature-id}" [name="{signature-name}"]>
    <content type="{text/plain | text/html}">{signature-value}</content>+
    [<cid>{contact-id}</cid>]
  </signature>
</ModifySignatureRequest>

<ModifySignatureResponse/>

- Changes attributes of the given signature.  Only the attributes specified in the request
  are modified.

- Server identify the signature by id, if the name attribute is present and is different
  from the current name of the signature, the signature will be renamed.

---------

<DeleteSignatureRequest>
  <signature [name="{signature-name}" | id="{signature-id}"]/>
</DeleteSignatureRequest>

<DeleteSignatureResponse/>

<-- must specify either 'name' or 'id' -->

---------

urn:zimbraMail

 mail error/codes: (includes service.*)

 Error code parameters:
       -  Error results have data parameters encoded in the
          soap:detail for the  error, in <a> elements:

          [<a n="name">VALUE</a>]* // error information (arguments,
               e.g. ID that was bad, or whatever)

       - See SOAP 1.1 or SOAP 1.2 section above.

 List of error codes:
   mail.MAINTENANCE        - in maintenance
   mail.NO_SUCH_MBOX       - no such mailbox
   mail.NO_SUCH_ITEM       - no such item
   mail.NO_SUCH_CONV       - no such converstation
   mail.NO_SUCH_MSG        - no such message
   mail.NO_SUCH_PART       - no such message part
   mail.NO_SUCH_FOLDER     - no such folder
   mail.NO_SUCH_TAG        - no such tag
   mail.NO_SUCH_CONTACT    - no such contact
   mail.NO_SUCH_CALITEM    - no such calendar item
   mail.NO_SUCH_APPT       - no such appointment
   mail.NO_SUCH_TASK       - no such task
   mail.NO_SUCH_DOC        - no such doc
   mail.NO_SUCH_UPLOAD     - no such upload
   mail.NO_SUCH_WAITSET    - no such waitset
   mail.QUERY_PARSE_ERROR  - couldn't parse search query (see below
                             for detailed error info)
   mail.NO_SUCH_CONTACT      - the specified contact id did not exist
   mail.MODIFY_CONFLICT      - if the modified date on a contact is different then one in the request
   mail.ALREADY_EXISTS
   mail.INVALID_ID
   mail.INVALID_SYNC_TOKEN
   mail.INVALID_NAME
   mail.INVALID_TYPE
   mail.INVALID_CONTENT_TYPE
   mail.IS_NOT_CHILD
   mail.CANNOT_CONTAIN
   mail.CANNOT_COPY
   mail.CANNT_TAG
   mail.CANNOT_PARENT
   mail.CANNOT_RENAME
   mail.CANNOT_SUBSCRIBE
   mail.IMMUTABLE_OBJECT
   mail.WRONG_MAILBOX
   mail.MODIFY_CONFLICT
   mail.TRY_AGAIN
   mail.SCAN_ERROR
   mail.UPLOAD_REJECTED
   mail.TOO_MANY_TAGS
   mail.TOO_MANY_UPLOADS
   mail.TOO_MANY_CONTACTS
   mail.UNABLE_TO_IMPORT_CONTACTS
   mail.UNABLE_TO_IMPORT_APPOINTMENTS
   mail.QUOTA_EXCEEDED
   mail.QUERY_PARSE_ERROR
   mail.MESSAGE_PARSE_ERROR
   mail.ADDRESS_PARSE_ERROR
   mail.ICALENDAR_PARSE_ERROR
   mail.MUST_BE_ORGANIZER
   mail.CANNOT_CANCEL_INSTANCE_OF_EXCEPTION
   mail.INVITE_OUT_OF_DATE
   mail.SEND_ABORTED_ADDRESS_FAILURE
   mail.SEND_PARTIAL_ADDRESS_FAILURE
   mail.SEND_FAILURE
   mail.TOO_MANY_QUERY_TERMS_EXPANDED
   mail.INVALID_COMMIT_ID



------------------------------

mail.QUERY_PARSE_ERROR details

Arguments:
   colNo - index into query string where the error occured
   curTok - current token being parsed (not always set)
   parserErr - localizable error code describing what happened.  Current codes:
         UNKNOWN_TEXT_AFTER_IS - user entered is:blah, blah unknown
         MISSING_TEXT_AFTER_TOFROMCC - user entered from: without required text
         LEXICAL_ERROR - Invalid character in search string or invalid operator name (e.g. "iis:foo")
         PARSER_ERROR - Missing operand after operator ("in:") or other general parse error, look at curTok
         INVALID_DATE - Couldn't parse argument to date: (before: after: etc) query.  Check curTok.

------------------------------

<!--

defaults aren't normally included in the response, they may
be shown here in examples though

-->

Email addresses:

 <e [t="{type}"] p="{personal-name}" a="{email-address}" d="{display-name}">{content}</e>

   {type} = (f)rom, (t)o, (c)c, (b)cc, (r)eply-to, (s)ender, read-receipt (n)otification, (rf) resent-from

         Type is only sent when an individual message is returned. In the
            list of conversations, all the email addresseses returned for a conversation are a subset
            of the participants. In the list of messages in a converstation, the email addressses are
            the senders.

         Note that "rf" addresses can only be *returned* on a message; when sending a message, "rf" is ignored

   {personal-name} = the comment/name part of an address
   {email-address} = the user@domain part of an address
   {display-name} = if we have personal, first word in "word1 word2" format, or last word in "word1, word2" format.
                    if no personal, take string before "@" in email-address.
   {content} = the original email string as specified by the sender (since we can't reliably reconstruct it
               out of the components)

MimeParts:

  <mp part="{mime-part-name}" body="{is-body}" s="{size-in-bytes} mid="{message-id} cid="{conv-id}" [truncated="1"]
       ct="{content-type}" name="{name}" cd="{content-disposition}" filename="{filename} ci="{content-id} cl="{content-location}">
    [<content>{content}</content>]
    <mp part="..." ...>
        <mp part="..." ...>
        </mp>
    </mp>
  </mp>

   {mime-part-name} = MIME part, "" means top-level part, 1 first part, 1.1 first part of a multipart inside of 1.
   truncated="1"  = the caller requested a maximum length (max="...") for inlined <content>, and this part's content was truncated down to that length

   {content-type} = MIME Content-Type. The mime type is the content of the element.
   {name}         = name attribute from the Content-Type param list
   {cont-disp}    = MIME Content-Disposition
   {filename}     = filename attribute from the Content-Disposition param list
   {content-id}   = MIME Content-ID (for display of embedded images)
   {content-location} = MIME/Microsoft Content-Location (for display of embedded images)
   {cont-desc} = MIME Content-Description.  Note cont-desc is not currently used in the code.
   {content} = the content of the part, if requested
   {is-body} = set to 1, if this part is considered to be the "body" of the message for display
               purposes.
   {message-id} = item id of the enclosing message, only present if <mp> is not enclosed within a <m> element

Messages:

  <m id="{message-id}" f="{flags}" s="{size}" d="{date}" cid="{conv-id}" l="{folder} origid="{original-id}">
   <content>....</content>*
   <e .../>*
   <su>{subject}</su>
   <fr>{fragment}</fr>

   <mid>{Message-ID header}</mid>
   [<inv>...</inv>]
   [<mp>...</mp>]
   [<content (url="{url}")>...</content>]
  </m>

  {content} = complete rfc822 message. only present during certain operations that deal with the raw content
              of a message.  There is at most 1 content element.
  {conv-id}  = converstation id. only present if <m> is not enclosed within a <c> element
  {size}     = size in bytes
  {flags}    = (u)nread, (f)lagged, has (a)ttachment, (r)eplied, (s)ent by me, for(w)arded, calendar in(v)ite,
               (d)raft, IMAP-\Deleted (x), (n)otification sent, urgent (!), low-priority (?), priority (+)
  {date}     = secs since epoch, from date header in message
  {original-id} = message id of message being replied to/forwarded (outbound messages only)
  {url}      = content servlet relative url for retrieving message content
  {subject}  = subject of the message, only returned on an expanded message
  {fragment} = first n-bytes of the message (probably between 40-100)
  <e .../>*  = zero or more addresses in the message, indentified by
  type (t="f|t|c")
  <inv ...>...</inv> = Parsed out iCal invite.  See soap-calendar.txt
  <mp ...>...</mp> =  The root MIME part of the message.  There is exactly 1 MIME part under
           a message element.  The "body" will be tagged with body="1", and the content
           of the body will also be present
  <content>  = the raw content of the message.  cannot have more than one of <mp>, <content> url, and <content> body.

Conversations:

  <c id="{conv-id}" tn="{tag-names}" n="{num-msgs}" [total="{all-msgs}"] d="{date}" f="{flags}" [elided="1"]>
    <e ...>*
    <su>{subject}</su>
    <fr>{fragment}</fr>
    <m>...</m>+
  </c>

  {date}      = date (secs since epoch) of most recent message in converstation
  {tag-names} = comma-separated list of tags on conv
  {flags}     = same flags as on <m> ("sarwfdxnu!?"), aggregated from all the conversation's messages
  {subject}   = subject of conversation
  {fragment}  = fragment of most recent msg in converstation
  {num-msgs}  = number of messages in conversation without IMAP \Deleted flag set
  {all-msgs}  = total number of messages in conversation

  <e ...>*     = zero or more participants in the converstations;
                 if elided="1", some participants are missing before the first returned <e> element
  <m>...</m>+  = one or more messages in the conversation. When doing search, the <m> elements returned
                 will only have the "id" attribute, and only messages that matched the search will be included.

Folders:

  <folder id="{folder-id}" name="{folder-name}" l="{parent-id}" [f="{flags}"] [color="{color}"]
       u="{unread}" [i4u="{imap-unread}"] n="{msg-count}" [i4n="{imap-count}"] s="{total-size}" [view="{default-type}"]
       [url="{remote-url}"] [activesyncdisabled="0|1"] [deletable="0|1"] [perm="{effective-perms}"] [rest="{rest-url}"] [webOfflineSyncDays="num-days"]>
    <acl [internalGrantExpiry="{millis-since-epoch}"] [guestGrantExpiry="{millis-since-epoch}"]>
      <grant perm="{rights}" gt="{grantee-type}" zid="{zimbra-id}" [expiry="{millis-since-epoch}"] [d="{grantee-name}"] [pw="{password-for-guest}"] [key="{access-key}"]/>*
    </acl>?
    <retentionPolicy> ... </retentionPolicy>?
  </folder>

  {folder-name}  = name of folder; whitespace is trimmed by server; 
  {parent-id}    = id of parent folder (absent for root folder)
  {flags}        = checked in UI (#), exclude free/(b)usy info, IMAP subscribed (*), does not (i)nherit rights from parent, is a s(y)nc folder with external data source, sync is turned on(~), folder does n(o)t allow inferiors / children
  {color}        = numeric; range 0-127; defaults to 0 if not present; client can display only 0-7
  {unread}       = number of unread messages in folder
  {imap-unread}  = number of unread messages with this tag, *including* those with the IMAP \Deleted flag set
  {msg-count}    = number of non-subfolder items in folder
  {imap-count}   = number of non-subfolder items in folder, *including* those with the IMAP \Deleted flag set
  {total-size}   = total size of all of non-subfolder items in folder
  {default-type} = (optional) default type for the folder; used by web client to decide which view to use;
                   possible values are the same as <SearchRequest>'s {types}: conversation|message|contact|etc
  {remote-url}   = url (RSS, iCal, etc.) this folder syncs its contents to
  {rest-url}     = url to the folder on rest interface for rest-enabled apps (such as wiki and notebook)
  {effective-perms} = for remote folders, the access rights the authenticated user has on the folder
                        - will contain the calculated (c)reate folder permission if the user has
                          both (i)nsert and (r)ead access on the folder
  {zimbra-id}    = the Zimbra account id, or if the {grantee-type} is "guest", the user's email address

    folders can have an optional ACL set on them for sharing.  if they do (and the authenticated
    user has (a)dminister rights on the folder), an <acl> element will be returned containing
    1 or more <grant> elements.

    an <acl> element has the following attributes:

    {internalGrantExpiry} = time when grants to internal grantees expire.
                            If not specified in the request, defaults to the maximum allowed expiry for internal grants.
                            If not specified in the response, defaults to 0.
                            Value of 0 indicates that these grants never expire.
    {guestGrantExpiry}    = time when grants to guest grantees expire.
                            If not specified in the request, defaults to the maximum allowed expiry for guest/external
                            user grants.  If not specified in the response, defaults to 0.
                            Value of 0 indicates that these grants never expire.

    a <grant> element has the following attributes:

    {rights}       = some combination of (r)ead, (w)rite, (i)nsert, (d)elete, (a)dminister, workflow action (x), view (p)rivate, view (f)reebusy
    {grantee-type} = the type of grantee: 
                     "usr", 
                     "grp", 
                     "dom" (domain), 
                     "cos",
                     "all" (all authenticated users), "pub" (public authenticated and unauthenticated access),
                     "guest" (non-Zimbra email address and password),
                     "key" (non-Zimbra email address and access key)
    {zid}          = grantee id
    {grantee-name} = name or email address of the principal being granted rights.
                     optional if {grantee-type} is "all"/"guest"/"pub".  When specified in a request,
                     this can be just the username portion of the address in the default domain.
    {pw}           = optional argument.  password when {grantee-type} is "guest"
    {key}          = optional argument.  access key when {grantee-type} is "key"
    {expiry}       = time when this grant expires.
                     For internal/guest grant:  If this attribute is not specified, the expiry of the grant is derived
                     from internalGrantExpiry/guestGrantExpiry of the ACL it is part of.  If this attribute is
                     specified (overridden), the expiry value can not be greater than the corresponding expiry value in
                     the ACL.
                     For public grant:  If this attribute is not specified, defaults to the maximum allowed expiry for
                     a public grant.  If not specified in the response, defaults to 0.  Value of 0 indicates that this
                     grant never expires.


Retention policy:

  <retentionPolicy>?
    <keep>
      <policy type="user" lifetime="{duration}"/>?
      <policy type="system" id="{id}" name="{name}" lifetime="{duration}"/>*
    </keep>
    <purge>
      <policy type="user" lifetime="{duration}"/>?
      <policy type="system" id="{id}" name="{name}" lifetime="{duration}"/>*
    </purge>
  </retentionPolicy>

    {duration} = a time duration value in provisioning format, e.g. "30d" for 30 days.

When applying system retention policy to a folder or tag, only the type and id
attributes are required.

Mountpoints:

  <link id="{folder-id}" name="{folder-name}" l="{parent-id}" [f="{flags}"] owner="{owner's-display-name}" zid="{owner's-zimbra-id}"
        rid="{id-of-shared-item}" ruuid="{UUID-of-shared-item}" oname="{owner's-name-for-item}" [color="{color}"] [view="{default-type}"]
        reminder="{reminder-enabled}"/>

  {folder-name}  = name of folder
  {parent-id}    = id of parent folder (absent for root folder)
  {flags}        = checked in UI (#), exclude free/(b)usy info, IMAP subscribed (*)
  {owner's-display-name} = primary email address of the owner of the linked-to resource
  {owner's-zimbra-id} = Zimbra id (guid) of the owner of the linked-to resource
  {id-of-shared-item} = item id of the linked-to resource in the remote mailbox
  {UUID-of-shared-item} = UUID of the linked-to resource in the remote mailbox
  {owner's-name-for-item} = The name presently used for the item by the owner
  {color}        = numeric; range 0-127; defaults to 0 if not present; client can display only 0-7
  {default-type} = (optional) default type for the folder; used by web client to decide which view to use;
                   possible values are the same as <SearchRequest>'s {types}:
                   conversation|message|contact|appointment|task|etc
  {reminder-enabled} = whether client should display reminder for appointments/tasks on this shared calendar

Tags:

  <tag id="{tag-id}" name="{tag-name}" [color="{color}"] u="{unread}" n="{item-count}"]>
    [<retentionPolicy> ... </retentionPolicy>]
  </tag>

  {tag-name}    = name of tag; cannot begin with '\' (avoid collsions with IMAP)
  {color}       = numeric; range 0-127; defaults to 0 if not present; client can display only 0-7
  {unread}      = number of unread messages with this tag
  {item-count}  = number of items with this flag

----------

<SearchRequest [limit="..."] [offset="..."] [sortBy="{sort-by}"] [groupBy="{group-by}"]
    [types="{types}"] [recip="*0|1|2"]
    [fetch="1|all|{item-id}"] [read="*0|1"] [max="{max-inlined-length}"] [html="*0|1"] [neuter="0|*1"] [needExp="1|*0"]
    [field={default_field}] [calExpandInstStart=TIME_IN_MSEC] [calExpandInstEnd=TIME_IN_MSEC]
    [allowableTaskStatus="need,inprogress,completed,canceled"]
    [includeTagDeleted="{include-imap-deleted}"] [includeTagMuted="{include-muted}"]
    [resultMode="{result-mode}"] [fullConversation="*0|1"] [inDumpster="*0|1"] [memberOf="1"]
    [warmup="*0|1"] [quick="*0|1"]>

  *(<header n="{header-name}/>)
  [<cursor id="prevId" [sortVal="prevSortValue"] [endSortVal="endSortValue"] [includeOffset="true|false"]/>]
  [   // OPTIONAL: client timezone identification (necessary to time-correct a user-specified date/time query)

      <tz id="timezonename"/>    // References an existing server-known timezone by ID

           OR

      // This format is identical to the one defined in soap-calendar.txt, make sure the documents stay in sync
      <tz
           id="timezonename"        // this name is ignored by the server, but it must be present
           stdoff="<minutes>"       // offset from UTC in standard time; local = UTC + offset
           [dayoff="<minutes>"]     // offset from UTC in daylight time; present only if DST is used
       >
       [                            // If daylight savings time is not used, <standard> and <daylight> must be
                                    // omitted.  If DST is used, both <standard> and <daylight> must be present.
           <standard                // time/rule for transitioning from daylight time to standard time
                                    // Either specify week/wkday combo, or mday.
               [
                   week="<number>"  // week number; 1=first, 2=second, 3=third, 4=fourth, -1=last
                   wkday="<number>" // day of week; 1=Sunday, 2=Monday, etc.
               ]
               mon="<number>"        // month; 1=January, 2=February, etc.
               [mday="<number>"]     // day of month (1..31)
               hour="<number>"       // transition hour (0..23)
               min="<number>"        // transition minute (0..59)
               sec="<number>"        // transition second; 0..59, usually 0
           />
           <daylight                 // time/rule for transitioning from standard time to daylight time
               [
                   week="<number>"
                   wkday="<number>"
               ]
               mon="<number>"
               [mday="<number>"]
               hour="<number>"
               min="<number>"
               sec="<number>"
           />
       ]  // optional STANDARD/DAYLIGHT definition
  ]   // optional TIMEZONE specifier

  [ // OPTIONAL: client locale identification
      <locale>LOCALE-STRING</locale>  // Where locale string is of the form LL-CC[-V+] where
                                      //     LL is two character language code
                                      //     CC is two character country code
                                      //     V+ is optional variant identifier string
                                      //
                                      // ISO Language Codes: http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
                                      // ISO Country Codes: http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
                                      //
                                      //
  ]

  <query>{query-string}</query>

</SearchRequest>

limit: an integer specifying the maximum number of results to return. It defaults to 10 if not specified, and is capped
  by 1000.
offset: an integer specifying the 0-based offset into the results list to return as the first result for this search
  operation.
For example, limit=10 offset=30 will return the 31st through 40th results inclusive.
For a response, the order of the returned results represents the sorted order.  There is not a separate index attribute
  or element.

if fetch="1" (or fetch="first") is specified, the first hit will be expanded inline (messages only at present)
if fetch="{item-id}", only the message with the given {item-id} is expanded inline
if fetch="all", all hits are expanded inline
    + if html="1" is also specified, inlined hits will return HTML parts if available
    + if read="1" is also specified, inlined hits will be marked as read
    + if neuter="0" is also specified, images in inlined HTML parts will not be "neutered"
    + if <header>s are requested, any matching headers are included in inlined message hits
    + if max="{max-inlined-length}" is specified, inlined body content in limited to the given length;
         if the part is truncated, truncated="1" is specified on the <mp> in question

Setting specifying which recipients should be returned.
recip="0" [default]
    returned sent messages will contain "From:" Senders only
    returned conversations will contain an aggregated list of "From:" Senders from messages in the conversation
    (maximum of 8) 
recip="1"
    returned sent messages will contain the set of "To:" Recipients instead of the Sender
    returned conversations whose first hit was sent by the user will contain that hit's "To:" recipients instead
    of the conversation's sender list (maximum of 8) 
recip="2"
    returned sent messages will contain the sets of both "From:" Senders and "To:" Recipients
    returned conversations will contain an aggregated list of "From:" Senders and "To:" Recipients from messages
    in the conversation (maximum of 8 of each) 

unless include-imap-deleted="1", items with the \Deleted flag are omitted from the search results (defaults to "0")
if include-muted="0", items with the \Muted flag are omitted from the search results (defaults to "1")

   {group-by} = DEPRECATED.  Use TYPES instead.
   {types} 	= comma-separated list.  Legal values are:
               conversation|message|contact|appointment|task|wiki|document
               (default is "conversation")

        **NOTE: only ONE of message, conversation may be set. If
                both are set, the first is used.

  {sort-by} = default is "dateDesc"
    Possible values:
      none|dateAsc|dateDesc|subjAsc|subjDesc|nameAsc|nameDesc|rcptAsc|rcptDesc|attachAsc|attachDesc|flagAsc|flagDesc|
      priorityAsc|priorityDesc|idAsc|idDesc|readAsc|readDesc
      * If sort-by is "none" then cursors MUST NOT be used, and some searches are impossible (searches that require
        intersection of complex sub-ops). Server will throw an IllegalArgumentException if the search is invalid.
    ADDITIONAL SORT MODES FOR TASKS: valid only if types="task" (and task alone):
      taskDueAsc|taskDueDesc|taskStatusAsc|taskStatusDesc|taskPercCompletedAsc|taskPercCompletedDesc

  {more-flag} = 1 if there are more search results remaining.
  {content-matched} = 1 if the content of the message matched
  <mp> elements will be set for the first response if fetch=1
  <hp> elements may be present if any attachments matched

  {field} = by default, text without an operator searches the CONTENT field.  By setting the
            {field} value, you can control the default operator. Specify any of the text operators that are
            available in query.txt, e.g. 'content:' [the default] or 'subject:', etc.  The date operators
            (date, after, before) and the "item:" operator should not be specified as default fields
            because of quirks in the search grammar.

  calExpandInstStart and calExpandInstEnd:
    If these are specified, and the search types include calendar item
    types (e.g. appointment), then the search results include the
    instances for calendar items within that range in the form
    described below.

    ***IMPORTANT NOTE: Calendar Items that have no instances within
    that range are COMPLETELY EXCLUDED from the results (e.g. not even
    an <appt> element>.  Calendar Items with no data (such as Tasks
    with no date specified) are included, but with no instance
    information***

  {result-mode} = Specifies the type of result
                  default is "NORMAL"
                  Valid choices:
                      NORMAL|IDS
                  NORMAL : everything
                  IDS    : only IDs

  fullConversation: By default, only matching messages are included in conversation results.
                    Set to 1 (true) to include all messages in the conversation, even if they don't match the search,
                    including items in Trash and Junk folders.

  memberOf : If set, Include the list of contact groups this contact is a member of.
             Note: use sparingly, there is a performance penalty associated with computing this information

  warmup: When this option is specified, all other options are simply ignored, so you can't include this option in
   regular search requests. This option gives a hint to the index system to open the index data and primes it for
   search. The client should send this warm-up request as soon as the user puts the cursor on the search bar. This will
   not only prime the index but also opens a persistent HTTP connection (HTTP 1.1 Keep-Alive) to the server, hence
   smaller latencies in subseqent search requests. Sending this warm-up request too early (e.g. login time) will be in
   vain in most cases because the index data is evicted from the cache due to inactivity timeout by the time you
   actually send a search request.

  quick: For performance reasons, the index system accumulates messages with not-indexed-yet state until a certain
   threshold and indexes them as a batch. To return up-to-date search results, the index system also indexes those
   pending messages right before a search. To lower latencies, this option gives a hint to the index system not to
   trigger this catch-up index prior to the search by giving up the freshness of the search results, i.e. recent
   messages may not be included in the search results.
   
  If needExp is "1", two additional flags will be included in <e> elements for messages 
  returned inline:
    - isGroup: "1" if the email address is a group
    - exp: present only when isGroup="1"
           "1" if the authed user can (has permission to) expand members in this group
           "0" if the authed user does not have permission to expand group members

  <cursor> (optional):
  - id, sortVal: These correspond to the last hit on the current page (assuming you're going forward, if you're backing
    up then they should be the first hit on the current page) or the selected item before changing the sort order.
    sortVal should be set to the value of the 'sf' (SortField) attribute. If you are changing the sort field, don't
    specify sortVal because 'sf' is sort field dependent. (In this case, the server supplements sortVal using the
    specified item ID. If the item no longer exist, the cursor gets cleared.) The server uses those attributes to find
    the spot in the new results that corresponds to your old position: even if some entries have been removed or added
    to the search results (e.g. if you are searching is:unread and you read some).
  - endSortVal (optional): Used for ranges to tell the cursor where to stop (non-inclusive) returning values
  - includeOffset (optional): If true, the response will include the cursor position (starting from 0) in the entire
    hits. This can't be used with text queries. Don't abuse this option because this operation is relatively expensive
    in the server.
  - Cursors are NOT legal if sortBy="none".

conversation result:
--------------------

<SearchResponse sortBy="sort-by" offset="..." more="{more-flag}">
  [<info>
    [<wildcard str="foo*" expanded="1|0"/>]
    [<suggest>{suggested query string}</suggest>]
   </info>]
  <c id="{conv-id}" tn="{tag-names}" n="{num-msgs}" u="{num-unread-msgs}" [total="{all-msgs}"] d="{date}" f="{flags} [mbx="UID"] sf="SORT-FIELD-VALUE">
    <e ...>*
    <su>{subject}</su>
    <fr>{fragment}</fr>
    [<m id="MATCHED_MSG_ID" f="{flags}" d="{date}">]+
  </c>*
</SearchResponse>


Info block:
            The <info> block is used to return general status
       information about your search.  The <wildcard> element tells
       you about the status of wildcard expansions within your search
       -- if expanded=1, then the wildcard was expanded and the
       matches are included in the search.  If expanded=0 then the
       wildcard was not specific enough and therefore no wildcard
       matches are included (exact-match *is* included in results).

message result:
---------------
<SearchResponse sortBy="sort-by" offset="..." more="{more-flag}">
   [<info>...</info>]
   <m id="{message-id}" tn="{tag-names}" f="{flags}" s="{size}" d="{date}" cid="{conv-id}" l="{location}" [mbx="UID"] sf="SORT-FIELD-VALUE" [cm="1"]>
     <e .../>*  <!- from only -->
     <su>{subject}</su>
     <fr>{fragment}</fr>
    *(<header n="{header-name}">header content</header>)
     [<mp>...</mp>] // if fetch=1, the <mp>'s of the hit (first hit only)
     <hp part="{mime-part-name}"/>+ // Hit Part -- indicator that the named part matched the search string
   </m>
</SearchResponse>

contact result:
---------------
<SearchResponse offset="..." more="{more-flag}" [sortBy="..."]>
   [<info>...</info>]
   <cn fileAsStr="..." rev="REVISION" sf="SORT-FIELD-VALUE" [d="{date}"] [md="{metadata-change-date}"]
                       id="id" [tn="tags"] l="folder">
      [<a n="...">...</a>]*
      [<memberOf>...</memberOf>]
   </cn>
</SearchResponse>

For example:

<SearchResponse offset="0" more="0" sortBy="dateDesc" xmlns="urn:zimbraMail">
   <cn fileAsStr="Rabbit, Peter" rev="3" sf="1501079792000" d="1501079792000" id="258" l="7">
      <a n="firstName">Peter</a>
      <a n="lastName">Rabbit</a>
      <a n="fullName">Rabbit, Peter</a>
      <a n="email">peter@rabbit.com</a>
      <memberOf>257</memberOf>
   </cn>
   <cn fileAsStr="contactGroup" rev="13" sf="1501080004000" d="1501080004000" id="257" l="7">
      <a n="nickname">contactGroup</a>
      <a n="fullName">contactGroup</a>
      <a n="type">group</a>
      <a n="fileAs">8:contactGroup</a>
      <m type="G" value="uid=admin,ou=people,dc=kiki,dc=fatkudu,dc=co,dc=uk"/>
      <m type="G" value="uid=gren,ou=people,dc=kiki,dc=fatkudu,dc=co,dc=uk"/>
      <m type="C" value="258"/>
      <m type="C" value="261"/>
   </cn>
</SearchResponse>

If one of the attributes is:
    <a n="type">group</a>
then the contact is a contact group (personal distribution list).  If this attribute is absent or its value
is "contact" then it is just a contact.

appointment result:
-------------------

<appt|task id="appointment_mail_item_id"
       tn="{tag-names}" f="{flags}" s="{size}" d="{date}" cid="{conv-id}" // standard hit data
       l="{location}" [mbx="UID"] sf="SORT-FIELD-VALUE" // standard hit data
       [fba="F|B|T|U"]
       [transp="O|T"]
       status="TENT|CONF|CANC"
       ptst="NE|TE|AC|DE|DG"
       [allDay="1"]             // if set, this is an "all day" appointment
       [otherAtt="1"]           // if set, this appointment has other attendees
       [alarm="1"]
       [recur="1"]              // if set, this is a recurring appointment
       [hasEx="1"]              // if set, this is a recurring appointment with exceptions
       [name="NAME"] [loc="LOCATION"]
       invId="default_invite_mail_item_id" compNum="default_invite_component_number"
       isOrg="default_am_i_organizer_flag"
       [priority="num"]
       [percentComplete="num"] // only if a <task>
       [dur="duration"]  // default duration; for appointments only
   >
     [<or d="friendly name" a="address">] // organizer, if available
     [<fr>DEFAULT FRAGMENT</fr>]

Expanded instance data -- only if calExpandInstStart and
    calExpandInstEnd are requested in the SearchRequest:

[    <inst
          [s="ms"]  // start time in millis
          [tzo="ms"]  // offset from GMT in milliseconds for start time in the
                    // time zone of the instance; this is useful because the
                    // instance time zone may not be the same as the time zone
                    // of the requesting client; when rendering an all-day
                    // appointment, the client must shift the appointment by
                    // the difference between the instance time zone and its
                    // local time zone to determine the correct date to render
                    // the all-day block
          [dueDate="ms"]  // due date in millis; for tasks only
          [tzoDue="ms"]   // similar to tzo, but for dueDate; tzoDue can be different from tzo if start date
                          // and due date lie on different sides of daylight savings transition
          [ex="1"]
          [ridZ="YYYYMMDD[ThhmmssZ]"]   // RECURRENCE-ID in "Z" (UTC) timezone, if this is an exception
          [ANY CHANGED PARAMETERS]
      >
          [<f>FRAGMENT IF DIFFERENT FROM DEFAULT</f>]
          [<dur DURATION>] // duration this instance if not same as default
          [<isOrg>] // isOrg flag if not same as default
          [<otherAtt>] // otherAtt flag if not same as default
    </inst>
]+

Next alarm trigger time and related info:
[   <alarmData
        nextAlarm="time in millis to show the alarm"
        alarmInstStart="start time of the meeting instance the alarm is reminding about"
        name="meeting subject"
        loc="meeting location"
        invId="invId" compNum="compNum" // these are used in GetMsg call
    >
      <alarm .../>  // detail of the alarm (repeat policy, text to show, etc.)
                    // See <alarm> definition in soap-calendar.txt
    </alarmData>
]

</appt|task>

   -- fba: actual free-busy status: Free, Busy, busy-Tentative, busy-Unavailable (a.k.a. OutOfOffice)
           While free-busy status is simply a property of an event that
           is set during creation/update, "actual" free-busy status is the true
           free-busy state that depends on appt/invite free-busy, event scheduling
           status (confirmed vs. tentative vs. cancel), and more importantly, the
           attendee's participation status.  For example, actual free-busy is
           busy-Tentative for an event with Busy free-busy value until the attendee
           has acted on the invite.
   -- transp: transparency: Opaque, Transparent
   -- status: status of event: TENTative, CONFirmed or CANCelled
   -- ptst: **your** participation status: NEeds-action, TEntative, ACcept, DEclined, DG (delegated)
   -- get the summary of appointments for a specified time period...
   -- otherAtt: 1 if there are other attendees to the meeting
   -- alarm: 1 if there are some alarms
   -- recur: 1 if this is a recurring appointment
   -- id is mail_item id of APPOINTMENT object
   -- invId is mail_item id of invite message with detailed information
   -- comp is component number (invite # within the message)
   -- parameters in the apptSum are "defaults" -- are same in instance unless specified


message-part result:
--------------------
<SearchResponse offset="..." more="{more-flag}">
   [<info>...</info>]
    <mp part="{mime-part-name}" s="{size-in-bytes} mid="{message-id}"
        ct="{content-type}" name="{name}" filename="{filename}" sf="SORT-FIELD-VALUE"/>

</SearchResponse>



-----------

<SearchConvRequest cid="conversation-id" [limit="..."] [offset="..."] [sortBy="{sort-by}"] [types="{types}"] [nest="0|1"]
    [fetch="0|1|u|u1|hits|all|!|hits!|u!|u1!|{comma-separated item-ids}] [max="{max-inlined-length}"] [html="1"] [read="1"] [neuter="0"] [needExp="1|0"] [wantContent="full|original|both"]>
  *(<header n="{header-name}/>)
  <query>{query-string}</query>
</SearchConvRequest>

  {conversation-id} = the conversation to search within.  REQUIRED.

  fetch:
    0|none|false: no messages are expanded inline
    1|first: the first matching message is expanded inline
    !: the first message in the conversation is expanded inline
    u|unread: all unread matching messages are expanded inline
    u1|unread-first: all unread messages (or the first message if there are no unread messages) are expanded inline
    u!: if there are unread matching messages, they are expanded inline, otherwise the first message is expanded
    u1!: if there are unread matching messages, they are expanded inline, otherwise the first message and the first matching message are expanded
    hits: all matching messages are expanded inline
    hits!: if there are matching messages, they are expanded inline, otherwise the first message is expanded
    all: all messages are expanded inline
    {comma-separated item-ids}: only the messages with {item-id} in the list are expanded inline

wantContent = "full" to get the complete message along with the quoted content
wantContent = "original" to get the message without quoted content
wantContent = "both" to get complete message as well as the message without quoted content
By default wantContent = "full"

Note: Quoted text identification is a best effort. It is not supported by any RFCs

  SEE SearchRequest for more info

if nest="0" on the request, response looks like this:

<SearchConvResponse sortBy="sort-by" offset="..." more="{more-flag}">
  [<info>...</info>]
  <m id="{message-id}" [cm="1"] f="{flags}" s="{size}" d="{date}" cid="{conv-id}" sf="SORT-FIELD-VALUE">
    <e .../>  <!- from only -->
    <su>{subject}</su>
    <fr>{fragment}</fr>
    *(<header n="{header-name}">header content</header>)
    [<mp>...</mp>] // if fetch=1, the <mp>'s of the hit (first hit only)
    <hp part="{mime-part-name}"/> // Hit Part -- indicator that the named part matched the search string
  </m>*
</SearchConvResponse>

if nest="1" on the request, response looks like this:

<SearchConvResponse sortBy="sort-by" offset="..." more="{more-flag}">
   [<info>...</info>]
   <c id="{conv-id}" tn="{tag-names}" n="{num-msgs}" [total="{all-msgs}"] f="{flags}">
     <m id="{message-id}" [cm="1"] f="{flags}" s="{size}" d="{date}" cid="{conv-id}" sf="SORT-FIELD-VALUE">
       <e .../>  <!- from only -->
       <su>{subject}</su>
       <fr>{fragment}</fr>
       [<mp>...</mp>] // if fetch=1, the <mp>'s of the hit (first hit only)
       <hp part="{mime-part-name}"/> // Hit Part -- indicator that the named part matched the search string
     </m>*
   </c>
</SearchConvResponse>

   {cm} = 1 if the message matched the specified query string

   SEE SearchResponse for more info


If needExp is "1", two additional flags will be included in <e> elements for messages 
returned inline:
  - isGroup: "1" if the email address is a group
  - exp: present only when isGroup="1"
         "1" if the authed user can (has permission to) expand members in this group
         "0" if the authed user does not have permission to expand group members

------------

<BrowseRequest browseBy="{browse-by}" [regex="{regex-string}"] [maxToReturn="{max}"]/>


<BrowseResponse>
 <bd freq="count">{browse-data}</bd>*
</BrowseResponse>

  {browse-by} = domains|attachments|objects
                where "objects" means objects in message body content recognized by Zimlets via <contentObject>
                configuration.
  {regex-string} = return only those results which match the specified regular expression
  {max} = return only a maximum number of entries as requested.  If more than {max}
          results exist, the server will return the first {max}, sorted by frequency
  {browse-data} =
      for attachments: content type (application/msword)

      for objects: object type (url, etc)

      for domains: domains (stanford.edu, etc)

      domain <bd> also contains the "h" attribute:

      <bd h="{h-flags}">stanford.edu</bd>

      which indicates whether or not the domain was from the "From", "To", or "Cc" header.
      Valid flags are always one of: "f", "t", "ft", "c", "fc", "tc", "ftc"

----------

<GetItemRequest>
  [<item [id="{item-id}"] [path="{path}"] [l="{folder-id}"]/>]
</GetItemRequest>

  the caller must specify one of:
    - an {item-id},
    - a fully-qualified {path}, or
    - both a {folder-id} and a relative {path}

<GetItemResponse>
  <folder|m|c|cn|wiki|etc. ...>
</GetItemResponse>

  a successful GetItemResponse will contain a single element appropriate for the type of the requested item
  if there is no matching item, a fault containing the code mail.NO_SUCH_ITEM is returned

----------

<GetFolderRequest [visible="0|1"] [needGranteeName="0|1"] [view="{folder-view-constraint}"] [depth="{subfolder-levels}"] [tr="{traverse-mountpoints}"]>
  [<folder [l="{base-folder-id}"] [path="{fully-qualified-path}"] [uuid="base-folder-uuid"]/>]
</GetFolderRequest>

  - a {base-folder-id}, a {base-folder-uuid} or a {fully-qualified-path} can optionally be specified;
      if none is present, the descent of the folder hierarchy begins at the mailbox's root folder (id 1).
      if {fully-qualified-path} is present and {base-folder-id} or {base-folder-uuid} is also present,
      the path is treated as relative to the folder that was specified by id/uuid.
      {base-folder-id} is ignored if {base-folder-uuid} is present.

  - if "visible" is 1, we include all visible subfolders of the specified folder
      when you have full rights on the mailbox, this is indistinguishable from the normal <GetFolderResponse>
      when you don't: folders you can see appear normally,
                      folders you can't see (and can't see any subfolders) are omitted
                      folders you can't see (but *can* see >=1 subfolder) appear as <folder id="{id}" name="{name}"> hierarchy placeholders

  - if *no* folders are visible and visible=1, the response looks like <GetFolderResponse/>

  - if "needGranteeName" is 0, grantee names in in folder grants (the d attribute in <grant>) are omitted.
    default for needGranteeName is 1.

  - if "view" is set then only the folders with matching view will be returned.  otherwise folders with any default views will be returned.

  - if "depth" is set to a non-negative number, we include that many levels of subfolders in the response
      (so if depth="1", we'll include only the folder and its direct subfolders)
      if depth is missing or negative, the entire folder hierarchy is returned

  - if "tr" is true, one level of mountpoints are traversed and the target folder's counts are applied to the local mountpoint
      if the root folder as referenced by {base-folder-id} and/or {fully-qualified-path} is a mountpoint, "tr" is automatically true
      mountpoints under mountpoints are not themselves expanded

<GetFolderResponse>
  <folder ...>
    <folder .../>
    <folder ...>
      <folder .../>
    </folder>
    <folder .../>
    [<link .../>]
    [<search .../>]
  </folder>
</GetFolderResponse>

GetFolderResponse always has exactly 1 folder element within it.  Without a base
folder ID that folder element will represent the virtual root folder.

If "tr" is true, broken links are rendered with broken="1" on the resulting <link> element.

----------

<GetConvRequest>
  <c id="{conv-id}" [fetch="1|all|{item-id}" max="{max-inlined-length}" html="0|1" needExp="0|1"]>
    *(<header n="{header-name}/>)
  </c>
</GetConvRequest>

GetConvRequest gets information about the 1 conversation named by id's value.
It will return exactly 1 conversation element.

if fetch="1|all" is included, the full expanded message structure is inlined
    for the first (or for all) messages in the conversation
if fetch="{item-id}", only the message with the given {item-id} is expanded inline

if <header>s are requested, any matching headers are inlined into the response
    (not available when raw="1")
    
needExp="1" to return group info (isGroup and exp flags) on <e> elements in the response
   (default is 0.)

<GetConvResponse>
  <c id="{conv-id}" [tn="{tag-names}"] n="{num-msgs}" [total="{all-msgs}"] [f="{flags}"]>
    <su>{subject}</su>
    <m id="{message-id}" [f="{flags}"] s="{size}" d="{date}" [tn="{tag-names}"]>
      <e .../>
      <fr>{fragment}</fr>
      <su>{subject}</su>
     </m>+
  </c>
</GetConvResponse>

------------

<GetMsgRequest>
  <m id="{msg-id}" [read="1"] [raw="1"] [max="{max-inlined-length}"] [useContentUrl="1|0"] [html="1"] [neuter="0"]
     [part="{part}"] [ridZ="YYYYMMDD[ThhmmssZ]"] [needExp="1|0"] [wantContent="full|original|both"]>
    *(<header n="{header-name}/>)
  </m>
</GetMsgRequest>

    The {msg-id} can contain a subpart identifier (e.g. "775-778") to return
    a message stored as a subpart of some other mail-item, specifically for
    Messages stored as part of Appointments

read="1" to mark the message as read, "0" to leave the read status unchanged.
  (default is 0.)
raw="1" to return the raw message content rather than a parsed mime structure;
    (default is "0".  if message too big or not ASCII, a content servlet URL is returned)
max="{max-inlined-length}" to limit the length of the text inlined into body <content> when raw="0"
    (default is "0", meaning no limit.)
useContentUrl="0|1".  If set, never inline raw <content> for messages, specify by "url" instead.
     Only applicable when raw is set.  Ignored when raw is unset.
     (Default is unset - meaning inline content unless it is too big, in which case the "url" method will be used)
html="1" to return defanged HTML content by default.
    (default is 0.)
neuter="1" to "neuter" <IMG> tags returned in HTML content; this involves switching
    the "src" attribute to "dfsrc" so that images don't display by default
    (default is 1.)
supply a "part" and the retrieved data will be on the specified message/rfc822 subpart.
    if the part does not exist or is not a message/rfc822 part, mail.NO_SUCH_PART

ridZ="YYYYMMDD[ThhmmssZ]" is used only when making GetMsg call to open an instance of a recurring appointment.
    the value specified is the date/time data of the RECURRENCE-ID of the instance being requested

needExp="1" to return group info (isGroup and exp flags) on <e> elements in the response
       (default is 0.)

wantContent = "full" to get the complete message along with the quoted content
wantContent = "original" to get the message without quoted content
wantContent = "both" to get complete message as well as the message without quoted content
By default wantContent = "full"

Note: Quoted text identification is a best effort. It is not supported by any RFCs

if <header>s are requested, any matching headers are inlined into the response
    (not available when raw="1")

<GetMsgResponse>
  <m id="{message-id}" [origid="..." rt="r|w"] [part="{part}"] f="{flags}" tn="{tag-names}" s="{size}" [d="{received-date}"] sd="{date-header}" [rd="{resent-date}"] l="{folder}" (cid="{conv}")
     (cif="{X-Zimbra-Calendar-Intended-For header}")
  >
    <e ... [isGroup="1|0"] [exp="1|0"]/>*
    <su>{subject}</su>
    <fr>{fragment}</fr>
    [<irt>{Message-ID header for message being replied to}</irt>]
    <mid>{Message-ID header}</mid>
    *(<header n="{header-name}">header content</header>)
    [<mp>...</mp>]
    [<shr><content>{share-announcement-in-xml}</content</shr>]
    [<dlSubs><content>{dl-subscription-request-in-xml}</content</dlSubs>]
    [<content (url="...")>...</content>]
    [<origContent>...</origContent>]
  </m>
</GetMsgResponse>

- origid/rt/irt are present only on drafts
- cif is set when the message is a calendar invite that was forwarded by another user, whose calendar is being
  managed by this user.  The attribute is set to the email of the forwarding user, for whom the invite was
  originally intended.
- when a message has been re-sent, there will be "rf" <e> elements (Resent-From) and an "rd" attribute (Resent-Date)
- origContent contains the message without quoted content

If needExp is "1" in the request, two additional flags will be included in <e> elements for the message:
  - isGroup: "1" if the email address is a group
  - exp: present only when isGroup="1"
         "1" if the authed user can (has permission to) expand members in this group
         "0" if the authed user does not have permission to expand group members

------------
<GetMsgMetadataRequest>
  <m ids="{msg-id-list}"/>
</GetMsgMetadataRequest>

<GetMsgMetadataResponse>
  (<m id="{message-id}" f="{flags}" tn="{tag-names}" s="{size}" d="{received-date}" l="{folder}" [cid="{conv}"]
      rev="{revision-number}" md="{date-metadata-changed}" ms="{change-sequence}"/>)*
</GetMsgMetadataResponse>

------------

<CreateFolderRequest>
  <folder name="..." [l="{parent-folder}"] [fie="1"] [view="{default-type}"] [color="{color}"] [rgb="{rgb-color}"] [f="{flags}"] [url="{url}"] [sync="1"]>
    <acl [internalGrantExpiry="{millis-since-epoch}"] [guestGrantExpiry="{millis-since-epoch}"]>
      <grant perm="{rights}" gt="{grantee-type}" zid="{zimbra-id}" [expiry="{millis-since-epoch}"] [d="{grantee-name}"] [key="{access-key}"]/>*
    </acl>?
  </folder>
</CreateFolderRequest>

  - if l is unset, name is the full path of the new folder; otherwise, name may not contain the folder separator '/'
  - if fie="1" is set, the server will fetch the folder if it already exists rather than throwing mail.ALREADY_EXISTS
  - if url is set and sync="1" (default), synchronize folder content on folder creation

<CreateFolderResponse>
  <folder id="..." name="..." l="{parent-folder}" [u="{unread count}"] [n="{msg count}"]/>
</CreateFolderResponse>

  - name and l are omitted on response for root folder
  - u and/or n attributes are present on response iff count > 0

---------

<ItemActionRequest>
  <!-- action can be preceeded by a "!" to negate it" -->
  <action id="{list}" op="delete|dumpsterdelete|recover|read|flag|priority|tag|move|trash|rename|update|color|lock|unlock|resetimapuid"
         [tn="{tag-name/list}"] [l="{folder}"] [name="{item-name}"] [color="{color}"] [rgb="{rgb-color}"]
         [tcon="[-]{constraint}"] [f="{flags}"]/>
</ItemActionRequest>

<ItemActionResponse>
  <action id="{list}" op="delete|read|flag|tag|move|trash|rename|update"/>
</ItemActionResponse>

  {list} = on input, list of items to act on, on output, list of
           items that were acted on
  [-]{constraint} = list of characters; constrains the set of affected items in a conversation
        t - include items in the Trash
        j - include items in Spam/Junk
        s - include items in the user's Sent folder (not necessarily "Sent")
        d - include items in Drafts folder
        o - include items in any other folder
    a leading '-' means to negate the constraint (e.g. "-t" means all messages not in Trash)

  For op="update", caller can specify any or all of: l="{folder}", name="{name}", color="{color}",
    tn="{tag-names}", f="{flags}".  When modifying tags or flags, all specified tags and flags
    are set, and all others are unset.

  In op="delete" action, the item is either permanently deleted if dumpster is not in use, or
  soft deleted to the dumpster.

  In op="dumpsterdelete" action, the item in the dumpster is permanently deleted.

  For op="recover", caller must specify l="{folder}".  The item is recovered from dumpster as a copy
  in the specified folder.  The dumpster copy is then deleted.

  For op="tag" or op="!tag", caller must specify tn="{tag-name}".  This changes the state of
    the specified tag without altering other tags.

  A trash operation on a remote item will cause it to be moved to the trash folder of its
  remote mailbox, not the local mailbox.

  <action op="color" id="{list}" color="{new-color} rgb="{new-color-in-rgb}"/>
    - change the item's color to new color.  only one of color or rgb attribute
      needs to be present.  if both are present rgb value takes precedence.
      rgb is specified as CSS style #rrggbb

  The <action> element in the response always contains the same id list that the client
  sent in the request.  Id's that were ignored due to constraints are included in the
  id list.

---------

<MsgActionRequest>
  <!-- action can be preceeded by a "!" to negate it" -->
  <action id="{list}" op="delete|read|flag|tag|move|update|spam|trash" [tag="{id}"] [l="{folder}"] [f="{flags}"] [tn="{tag-names}"] [color="{color}"]/>
</MsgActionRequest>

<MsgActionResponse>
  <action id="{list}" op="delete|read|flag|tag|move|update|spam|trash"/>
</MsgActionResponse>

  {list} = on input, list of messages to act on, on output, list of
           messages that were acted on
           list may only have 1 element for action "spam"

  For op="update", caller can specify any or all of: l="{folder}", name="{name}", color="{color}",
    tn="{tag-names}", f="{flags}".

  for op="!spam", can optionally specify a destination folder

  See <ItemActionRequest> for more details.

---------

<ConvActionRequest>
  <!-- action can be preceeded by a "!" to negate it" -->
  <action id="{list}" op="delete|read|flag|priority|tag|move|spam|trash|mute"
      [tag="{id}"] [l="{folder}"] [tcon="{constraint}"] [tcon="[-]{constraint}"] [acctRelPath="{relative-folder-path}"]/>
</ConvActionRequest>

<ConvActionResponse>
  <action id="{list}" op="delete|read|flag|tag|move|spam|trash"/>
</ConvActionResponse>

  {list} = on input, list of conversations to act on, on output, list of
           conversations that were acted on
           list may only have 1 element for action "spam"
  [-]{constraint} = list of characters; constrains the set of affected items in a conversation
        t - include items in the Trash
        j - include items in Spam/Junk
        s - include items in the user's Sent folder (not necessarily "Sent")
        d - include items in Drafts folder
        o - include items in any other folder
    a leading '-' means to negate the constraint (e.g. "-t" means all messages not in Trash)

  for op="!spam", can optionally specify a destination folder

  for op="mute" or "!mute", any {constraint} is ignored

  For op="move", "acctRelPath" attr can also be used to specify the target folder, in terms of the relative path
    from the account / data source's root folder. The target account / data source is identified based on where the
    messages in this conversation already reside. If a conversation contains messages belonging of multiple accounts /
    data sources then it would not be affected by this operation.

  See <ItemActionRequest> for more details.

---------

<FolderActionRequest>
  <action id="{list}" op="read|delete|rename|move|trash|empty|color|[!]grant|revokeorphangrants|url|import|sync|fb|[!]check|update|[!]syncon|retentionpolicy|[!]disableactivesync|webofflinesyncdays" [l="{target-folder}"]
                      [name="{new-name}"] [color="{new-color}"] [rgb="{rgb-color}"] [zid="{grantee-zimbra-id}"] [url="{target-url}"]
                      [excludeFreeBusy="{exclude-free-busy-boolean}"] [numDays="{web-offline-sync-days}"]>
    [<grant perm="..." gt="..." zid="..." [expiry="{millis-since-epoch}"] [d="..."] [key="..."]/>]
    [<retentionPolicy> ... </retentionPolicy>]
  </action>
</FolderActionRequest>

<FolderActionResponse>
  <action id="{list}" op="read|delete|empty|rename|move|trash|color|grant|url|import|sync|fb|[!]check|update" [zid="{grantee-zimbra-id}"]/>
</FolderActionResponse>

Actions:
  <action op="read" id="{list}"/>
    - mark all items in the folder as read

  <action op="delete" id="{list}"/>
    - hard-delete the folder, all items in the folder, and all the folder's subfolders

  <action op="empty" id="{list}" [recusive="{delete-subfolders}"]/>
    - hard-delete all items in the folder (and all the folder's subfolders if "recursive" is set)

  <action op="rename" id="{list}" name="{new-name}" [l="{new-folder}"]/>
    - change the folder's name (and optionally location);
      if {new-name} begins with '/', the folder is moved to the new path and any missing path elements are created

  <action op="move" id="{list}" l="{new-folder}"/>
    - move the folder to be a child of {target-folder}

  <action op="trash" id="{list}"/>
    - move the folder to the Trash, marking all contents as read and
      renaming the folder if a folder by that name is already present in the Trash

  <action op="color" id="{list}" color="{new-color} rgb="{new-color-in-rgb}"/>
    - see ItemActionRequest

  <action op="grant" id="{list}">
    <grant perm="..." gt="..." zid="..." [expiry="{millis-since-epoch}"] [d="..."] [key="..."]/>
  </action>
    - add the <grant> object to the folder

  <action op="!grant" id="{list}" zid="{grantee-zimbra-id}"/>
    - revoke access from {grantee-zimbra-id}
        (you can use "00000000-0000-0000-0000-000000000000" to revoke acces granted to "all"
        or use "99999999-9999-9999-9999-999999999999" to revoke acces granted to "pub" )

  <action op="revokeorphangrants" id="{folder-id}" zid="{grantee-zimbra-id}" gt="{grantee-type}"/>
    - revoke orphan grants on the folder hierarchy granted to the grantee specified by zid and gt
      "orphan grant" is a grant whose grantee object is deleted/non-existing.  Server will throw
      INVALID_REQUEST if zid points to an existing object,
      Only supported if gt is usr|grp|cos|dom; otherwise server will throw INVALID_REQUEST.

  <action op="url" id="{list}" url="{target-url}" [excludeFreeBusy="{exclude-free-busy-boolean}"]/>
    - set the synchronization url on the folder to {target-url}, empty the folder, and\
      synchronize the folder's contents to the remote feed, also sets {exclude-free-busy-boolean}

  <action op="sync" id="{list}"/>
    - synchronize the folder's contents to the remote feed specified by the folder's {url}

  <action op="import" id="{list}" url="{target-url}"/>
    - add the contents to the remote feed at {target-url} to the folder [1-time action]

  <action op="fb" id="{list}" excludeFreeBusy="{exclude-free-busy-boolean}"/>
    - set the excludeFreeBusy boolean for this folder (must specify {exclude-free-busy-boolean})

  <action op="[!]check" id="{list}"/>
    - set or unset the "checked" state of the folder in the UI

  <action op="[!]syncon" id="{list}"/>
    - set or unset the "sync" flag of the folder to sync a local folder with a remote source
    
  <action op="[!]disableactivesync" id="{list}"/>
    - If set, disable access to the folder via activesync.
      Note: Only works for user folders, doesn't have any effect on system folders.

  <action op="webofflinesyncdays" id="{list}" numDays="{web-offline-sync-days}"/>
    - set the number of days for which web client would sync folder data for offline use
      {web-offline-sync-days} must not be greater than value of zimbraWebClientOfflineSyncMaxDays account attribute

  <action op="update" id="{list}" [f="{new-flags}"] [name="{new-name}"] [l="{target-folder}"] [color="{new-color}"] [view="{new-view}"]>
    [<acl><grant .../>*</acl>]
  </action>
    - do several operations at once:
          name="{new-name}"        to change the folder's name
          l="{target-folder}"      to change the folder's location
          color="{new-color}"      to set the folder's color
          view="{new-view}"        to change folder's default view (useful for migration)
          f="{new-flags}"          to change the folder's exclude free/(b)usy, checked (#), and IMAP subscribed (*) state
          <acl><grant ...>*</acl>  to replace the folder's existing ACL with a new ACL
          

  {list} = on input, list of folders to act on, on output, list of folders that were acted on;
           list may only have 1 element for actions empty, sync, fb, check, !check, url, import, grant, !grant, revokeorphangrants,
           !flag, !tag, syncon, !syncon, retentionpolicy

output of "grant" action includes the zimbra id the rights were granted on

note that "delete", "empty", "rename", "move", "color", "update" can be used on search folders as well as standard folders

---------

<TagActionRequest>
  <action op="read|rename|color|delete|update|retentionpolicy" [id="{tag-ids}" | tn="{tag-names}"] [name="..."] [color="..."]>
    [<retentionPolicy> ... </retentionPolicy>]
  </action>
</TagActionRequest>

  - caller must supply one of "id" or "tn"
  - if op="update", the caller can specify "name" and/or "color"

<TagActionResponse>
  <action op="read|rename|color|delete|update|retentionpolicy" id="..." [tn="..."] /> <!-- iff op was successful -->
</TagActionResponse>

  - "tn" present in response only if "tn" present in request

--------------

<GetTagRequest/>

<GetTagResponse>
  <tag id="..." name="..." color="..." [u="{unread_count}"] [n="{item-count}"]/>+
</GetTagResponse>

u,n attributes present iff count > 0
---------

<CreateTagRequest>
  <tag name="..." (color="...")/>
</CreateTagRequest>

<CreateTagResponse>
  <tag (same as GetTagResponse)/>
</CreateTagResponse>

---------

<GetSearchFolderRequest>
  <!-- get all by default -->
</GetSearchFolderRequest>

<GetSearchFolderResponse>
  <search id="..." name="..." query="..." [types="..."] [sortBy="..."] l="{folder}"/>+
</GetSearchFolderResponse>

---------

<CreateSearchFolderRequest>
  <search name="..." query="..." [types="..."] [sortBy="..."] l="{folder}" [f="{flags}"] [color="{color}"] [rgb="{rgb-color}"]/>
</CreateSearchFolderRequest>

<CreateSearchFolderResponse>
  <search id="..." name="..." query="..." [types="...] [sortBy="..."] l="{folder}"/>
</CreateSearchFolderResponse>

---------

<ModifySearchFolderRequest>
  <search id="..." query="..." [types="..."] [sortBy="..."]/>
</ModifySearchFolderRequest>

<ModifySearchFolderResponse>
  <search id="..." name="..." query="..." [types="...] [sortBy="..."] l="{folder}"/>  <!-- iff it was modified -->
</ModifySearchFolderResponse>

---------

<CreateMountpointRequest>
  <link l="{folder}" name="{mountpoint-name}" [view="..."] [color="{color}"] [rgb="{rgb-color}"] [f="{flags}"] [fie="1"]
         [zid="{owner's-zimbra-id}" | owner="{owner's-email-address}"] [rid="{id-of-shared-item}" | path="{path-to-shared-item}"]
         [reminder="0"]/>
</CreateMountpointRequest>

  - caller must specify one of (zid | owner) and one of (rid | path)
  - reminder=1 means client should display reminders for shared appointments/tasks

<CreateMountpointResponse>
  <link id="{created-link-item-id}" l="{folder}" name="..." [view="..."]/>
</CreateMountpointResponse>

---------

<EnableSharedReminderRequest>
  <link id="{mountpoint id}" reminder="0|1"/>
</EnableSharedReminderRequest

  - enable/disable reminders for shared appointments/tasks

<EnableSharedReminderResponse/>

---------

# origid will be present if this is a reply or forward
# TODO: indicate whether to save in SentMail (or some other folder)

+  supports (f)rom, (t)o, (c)c, (b)cc, (r)eply-to, (s)ender, read-receipt (n)otification "type" on <e> elements
+  only allowed one top-level <mp> but can nest <mp>s within if multipart/*
+    a leaf <mp> can have inlined content (<mp ct="{content-type}"><content>...</content></mp>)
+    a leaf <mp> can have referenced content (<mp><attach ...></mp>)
+    any <mp> can have a Content-ID header attached to it
+  on reply/forward, set origid on <m> element and set rt to "r" or "w", respectively
+  can optionally set identity-id to specify the identity being used to compose the message
+  if noSave="1", a copy will *not* be saved to sent regardless of account/identity settings
+  if fetchSavedMsg="1", return the copy of the sent message, if it was saved, in the response
+  can set priority high (!) or low (?) on sent message by specifying "f" attr on <m>
+  if "did" is specified, then the draft item will be removed if the SendMsg is successful.

<SendMsgRequest [suid="{send-uid}"] [needCalendarSentByFixup="0|1"] [isCalendarForward="0|1"] [noSave="0|1"] [fetchSavedMsg="0|1"]>
  <m [f="!|?"] [origid="..." rt="r|w"] [idnt="{identity-id}"] [dsId="{datasource-id}"] [did="{saved-draft-id}"]>
    <e t="{type}" a="{email-address}" p="{personal-name}"/>+
    <su>{subject}</su>*
    [<header name="{header-name}">{header-value}</header>]*
    [<irt>{Message-ID header for message being replied to}</irt>]
    <mp ct="{content-type}" [ci="{content-id}"]>
      <content>...</content>
    </mp>
    <attach [aid="{attach-upload-id}[,{attach-upload-id}]"]>
      [<m id="{message-id}" [optional="0|1"]/>]*
      [<mp mid="{message-id}" part="{part-id}" [optional="0|1"]/>]*
      [<cn id="{contact-id}" [optional="0|1"]/>]*
      [<doc (id="{document-id}" | path="{document-path}") [optional="0|1"]/>]*
    </attach>
  </m>
</SendMsgRequest>

   or, if you want to compose the message remotely, upload it via
   FileUploadServlet, and submit it through our server:

<SendMsgRequest [suid="{send-uid}"] [needCalendarSentByFixup="0|1"] [isCalendarForward="0|1"] [fetchSavedMsg="0|1"]>
  <m aid="{uploaded-MIME-body-ID}" [origid="..." rt="r|w"]/>
</SendMsgRequest>

Composing the message based on existing draft:

If you want to compose the message based on existing draft use the following. The parameter sfd="1" (sendFromDraft) instructs
the server to construct message based on the "did" (id of the draft). The draft item will be removed if the SendMsg is successful.

<SendMsgRequest [suid="{send-uid}"] [needCalendarSentByFixup="0|1"]  [isCalendarForward="0|1"] [noSave="0|1"] [fetchSavedMsg="0|1"]>
  <m [f="!|?"] [origid="..." rt="r|w"] [idnt="{identity-id}"] did="{saved-draft-id}" sfd="1"/>
</SendMsgRequest>

Or if you want to compose the message based on existing draft, but want to make some changes such
as subject/recipient follow the below steps.
  
1> Send <GetMsgRequest> with the draft id as message id, and get all the data for the saved message.

2> Use <SendMsgRequest> with the data retrieved from <GetMsgResponse> and set the "did" parameter to draft id.
   This will ensure that the draft gets removed if the SendMsg is successful. 

# If the message is saved to the sent folder then the id of the message is returned.
# Otherwise, no id is returned -- just a <m></m> is returned.
<SendMsgResponse>
  <m id="..." />
</SendMsgResponse>

# If fetchSavedMsg="1", copy of the sent message, if it was saved, is returned in the response
<SendMsgResponse>
  <m id="..." ...>
    <e .../>
    ...
    <su>Speaking of animals</su>
    <fr>...</fr>
    <mp part="" ct="multipart/mixed"/>
      <mp part="1" ct="text/plain" body="1"/>
        <content>This is another frag that is part of a bigger message. blah blah blah</content>
      </mp>
      ...
    </mp>
  </m>
</SendMsgResponse>

needCalendarSentByFixup - Add SENT-BY parameter to ORGANIZER and/or ATTENDEE
                          properties in iCalendar part when sending message
                          on behalf of another user
                          default is 0

isCalendarForward - Indicates whether this a forward of calendar invitation in which
                    case the server sends Forward Invitation Notification, default is 0.

  {send-uid} - an optional client-generated unique identifier string for the send
               if the SendMsg request is re-sent but the message has not been modified, the client should use
                   the same {send-uid} and the server will try to check the status of the previous SendMsg attempt

  {header-name}, {header-value} - custom RFC822 header name and value respectively. Only header names specified in
    zimbraCustomMimeHeaderNameAllowed global config are allowed for security reasons.

dsId - Id of the data source in case SMTP settings of that data source must be used for sending the message.

----------------------------

# origid will be present if this is a reply or forward
# Can we have more than one From: address?
# TODO: indicate folder to save in (defaults to Drafts)

+  only allowed one top-level <mp> but can nest <mp>s within if multipart/*
+  on reply/forward, set origid on <m> element and set rt to "r" or "w", respectively
+  can optionally set identity-id to specify the identity being used to compose the message
+  if updating an existing draft, set "id" attr on <m> element
+  can refer to parts of existing draft in <attach> block
+  drafts default to the Drafts folder
+  setting folder/tags/flags/color occurs *after* the draft is created/updated, and if it fails the content *WILL STILL BE SAVED*
+  can optionally set autoSendTime to specify the time at which the draft should be automatically sent by the server

<SaveDraftRequest>
  <m [id="{existing-draft-id}"] [origid="..." rt="r|w"] [idnt="{identity-id}"] [l="{folder}"] [f="{flags}"] [tn="{tag-names}"] [color="{color}"] [autoSendTime="{millis-since-epoch}"]>
    <e t="{type}" a="{email-address}" p="{personal-name}"/>+
    <su>{subject}</su>*
    [<header name="{header-name}">{header-value}</header>]*
    [<irt>{Message-ID header for message being replied to}</irt>]
    <mp ct="{content-type}">
      <content>...</content>
    </mp>
    <attach [aid="{attach-upload-id}"]>
      [<m id="{message-id}" [optional="0|1"]/>]*
      [<mp mid="{message-id}" part="{part-id}" [optional="0|1"]/>]*
      [<cn id="{contact-id}" [optional="0|1"]/>]*
      [<doc (id="{document-id}" | path="{document-path}") [optional="0|1"]/>]*
    </attach>
  </m>
</SaveDraftRequest>

   or, if you want to compose the message remotely, upload it via
   FileUploadServlet, and submit it through our server:

<SaveDraftRequest>
  <m aid="{uploaded-MIME-body-ID}" [id="{existing-draft-id}"]
    [origid="..." rt="r|w"] [l="{folder}"] [f="{flags}"] [tn="{tag-names}"] [color="{color}"] [autoSendTime="{millis-since-epoch}"]/>
</SaveDraftRequest>


# The id of the saved draft is returned
<SaveDraftResponse>
  <m id="{message-id}" f="{flags}" tn="{tag-names}" s="{size}" [d="{received-date}"]
    sd="{date-header}" l="{folder}" (cid="{conv}") [autoSendTime="{millis-since-epoch}"]
    [idnt="{identity-id}"]>
    <e .../>*
    <su>{subject}</su>
    <irt>{Message-ID header for message being replied to}</irt>
    <fr>{fragment}</fr>
    <mid>{Message-ID header}</mid>
    [<mp>...</mp>]
    [<content (url="...")>...</content>]
  </m>
</SaveDraftResponse>

The identity referenced by {identity-id} specifies the folder where the sent message
is saved.

----------------------------

<SendDeliveryReportRequest mid="{message-id}"/>

<SendDeliveryReportResponse/>

----------------------------

+ supports (f)rom, (t)o, (c)c, (b)cc, (s)ender "type" on <e> elements
+   (these get mapped to Resent-From, Resent-To, Resent-CC, Resent-Bcc, Resent-Sender
+    headers, which are prepended to copy of existing message)
+ aside from these prepended headers, message is reinjected verbatim

<BounceMsgRequest>
  <m id="{id-of-msg-to-resend}">
    <e .../>*
  </m>
</BounceMsgRequest>

<BounceMsgResponse/>

----------------------------

  <AddMsgRequest [filterSent="0|1"]>
    <m l="{folder}" [f="{flags}"] [tn="{tag-names}"] [d="{received-date}"] [aid="{uploaded-MIME-body-ID}"] [noICal="0|1"]>
       <content>
          ...
       </content>
       [
         <inv uid="UID">...</inv> # MUST have UID
       ]
      ...
    </m>
  </AddMsgRequest>

  {flags} = (u)nread, (f)lagged, has (a)ttachment, (r)eplied, (s)ent by me, for(w)arded,
            (d)raft, deleted (x), (n)otification sent
  {tag-names} = comma-separated list of tag names
  {folder} = folder pathname (starts with '/') or folder ID
  {received-date} = (optional) time the message was originally received, in MILLISECONDS since the epoch
  {uploaded-MIME-body-ID} = ID of message uploaded via FileUploadServlet
  {noICal} = if TRUE, then don't process iCal attachments.  Default is FALSE.
     TODO: even if noICal is true, calendar should still link message to existing appointment
           (by UID) if the appointment already exists.
  {filterSent} = If TRUE, then do outgoing message filtering if the msg is being added to the Sent
                 folder and has been flagged as sent. Default value is FALSE.

  Note that the <m> element should include the <content> element with the
  entire message's content.  (Omit <content> if you specify an "aid" attribute.)
  No <mp> elements should be provided within <m>.

# Returns the Message's ID just created
<AddMsgResponse>
  <m id="{message-id}" f="{flags}" tn="{tag-names}" s="{size}" d="{received-date}" l="{folder}" [cid="{conv}"]
      rev="{revision-number}" md="{date-metadata-changed}" ms="{change-sequence}"/>
</AddMsgResponse>

----------------------------

  <RemoveAttachmentsRequest>
    <m id="{message-id}" part="{list-of-part-ids-to-remove}">
  </RemoveAttachmentsRequest>

  {list-of-part-ids-to-remove} = comma-separated list of part IDs to strip from existing message body

# NOTE that this operation is effectively a create and a delete, and thus the message's item ID will change

  <RemoveAttachmentsResponse>
    <m id="{message-id}" f="{flags}" tn="{tag-names}" s="{size}" d="{received-date}" l="{folder}" [cid="{conv}"]
        rev="{revision-number}" md="{date-metadata-changed}" ms="{change-sequence}"/>
  </RemoveAttachmentsResponse>

----------------------------

Contacts:

  <cn id="{contact-id}" [tn="{tag-names}"] [f="{flags}"] md="{modified-date}" [l="{folder}"] [fileAsStr="{file-as}"]>
    <a n="{attr-name}">{attr-data}</a>+
    <a n="{attr-name}" aid="{upload-id}"/>*
    <a n="{attr-name}" id="{item-id}" [part="{subpart-name}"]/>*
    <a n="{attr-name}" part="{part-id}"/>*  <-- only valid when modifying an existing contact -->
    <m type="{member-type}" value="{member-value}"/>*
  </cn>

  {contact-id} = unique contact id
  {flags} = (f)lagged, has (a)ttachment
  {modified-date}  = secs since epoch, date contact was modified
  {file-as} = current "file as" string for display/sorting purposes; *cannot* be used to *set* the file-as value
  {attr-name} = name of the attribute (firstName, etc)

  {folder-id} = id of folder to create contact in. Un-specified means use the default Contacts folder.

  To add attachments, specify an {upload-id} instead of providing {attr-data} on the attr
    alternatively, specify an {item-id} to attach, with an optional {subpart-name} for contacts and messages
    when editing an existing contact, can omit the {item-id} and we'll assume it's the contact being edited

  Date related attributes like "birthday" and "anniversary" SHOULD use "yyyy-MM-dd" format or, if the year
  isn't specified "--MM-dd" format

  when contacts are returned, they look like:

  <cn id="{contact-id}" tn="{tag-names}" f="{flags}" md="{modified-date}" l="{folder}" fileAsStr="{file-as}">
    <a n="{attr-name}">{attr-data}</a>+
    <a n="{attr-name}" size="{attach-size}" ctype="{attach-content-type}" filename="{attach-filename}" part="{part-id}"/>*
  </cn>

----------

<CreateContactRequest [verbose="0|1"]>
  <cn [l="{folder-id}"] [tn="{tag-names}"]>
     <a>...</a>+
     <m type="{member-type}" value="{member-value}"/>*
  </cn>
</CreateContactRequest>

  <m> : valid only if the contact being created is a contact group (has attribute type="group")
  {member-type} = C|G|I
                  C: reference to another contact
                  G: reference to a GAL entry
                  I: inlined member (member name and email address is embeded in the contact group)

  {member-value} = if type=C: itemId of another contact.  If the referenced contact is in a
                              shared folder, the itemId must be qualified by zimbraId of the
                              owner.  e.g. {zimbraId}:{itemId}
                   if type=G: GAL entry ref (returned in SearcgGalResponse)
                   if type=I: name and email address in the form of: "{name}" <{email}>

  or, if you have an existing vCard to add, you can specify a <vcard> element with *one* of
    -- inlined content
    -- mid/part attributes specifying an existing message part
    -- aid attribute specifying an uploaded text/calendar file

<CreateContactRequest [verbose="0|1"]>
  <cn [l="{folder-id}"] [tn="{tag-names}"]>
    <vcard [mid="{message-id}" part="{part-identifier}] [aid={uploaded-attachment-id"}"]>
[BEGIN:VCARD
...
END:VCARD]
    </vcard>
  </cn>
</CreateContactRequest>


<CreateContactResponse>
   (<cn> definition above)
</CreateContactResponse>

  {folder-id} = id of folder to create contact in. Un-specified means use the default Contacts folder.
  {tag-names} = list of tags to apply to the created contact

  -- if "verbose='0'" (defaults to '1') was specified on the request, the returned <cn>
         is just a placeholder containing the new contact ID (i.e. <cn id="{id}"/>)

----------

<ModifyContactRequest [replace="{replace-mode}"] [verbose="0|1"]>
  <cn id="..." [tn="{tag-names}"]>
    <a n="{name}" [op="{op}"]>{attr-value}</a>+
    <m op="{member-op}" type="{member-type}" value="{member-value}"/>*
  </cn>
</ModifyContactRequest>

 {tag-names} = list of tags to apply to the created contact
 {attr-value} = new attribute value. If empty (<a/>), then the attribute will be removed.

 {replace-mode} = 0 (false)|1 (true) [0 is default]

  if {replace-mode} is 1, all attrs and group members in the specified contact are replaced with specified attrs
  and group members, otherwise the attrs and group members are merged with the existing contact.

  {op} = + | -
         + : add the value
         - : remove the value

        When {replace-mode} is 1, {op} must NOT be specified.  If it is, INVALID_REQUEST will be thrown
        When {replace-mode} is 0:
            (1) if op is not present:
                   if {attr-value} is empty, remove the field
                   otherwise, replace the field with this value

            (2) if op is present:
                   if {attr-value} is empty, throw INVALID_REQUEST
                   - otherwise, add/remove the specified value.

  {member-op} = + | - | reset
         +     : add the value - {member-type} and {member-value} are required
         -     : remove the value - {member-type} and {member-value} are required
         reset : Delete all pre-existing members - new members can be specified with later <m> elements using "+"
                 {member-type} and {member-value} are ignored
        When {replace-mode} is 1, {member-op} must NOT be specified.  If it is, INVALID_REQUEST will be thrown
        When {replace-mode} is 0, {member-op} is required.

  When modifying tags, all specified tags are set and all others are unset.  If tn="{tag-names}" is NOT specified
  then any existing tags will remain set.

<ModifyContactResponse>
   <cn ...>
     <a n="...">...</a>
     <m type="{member-type}" value="{member-value}"/>*
   </cn>
</ModifyContactResponse>

NOTE: should we return modified attrs in response?

  -- if verbose='0' (defaults to '1') was specified on the request, the returned <cn>
         is just a placeholder containing the contact ID (i.e. <cn id="{id}"/>)

----------

<GetContactsRequest [sortBy="nameAsc|nameDesc"] [sync="1"] [l="{folder-id}"] [derefGroupMember="1"] 
    [returnHiddenAttrs="1"] [maxMembers="{max-members}"] [returnCertInfo="1"] [memberOf="1"]>
  <a n="..."/>*
  <ma n="..."/>*
  <cn id="{contact-id}"/>*
</GetContactsRequest>

  if sync="1" present, return modified date (md) on contacts.
  if l="{folder-id}" is present, return only contacts in the specified folder.
  if <a n="..."/> present, return only the specified attribute(s).
  if <ma n="..."/> present, return only the specified attribute(s) for derefed members, applicable only when derefGroupMember=1.
  if <cn id="..."/> present, only get the specified contact(s). Use multiple elements to request multiple contacts.

  {derefGroupMember} : Contact members can be:
                           - inline data of name and email address
                           - a reference to a local contact or a shared contact,
                           - a GAL entry
                       0 (default) - do not deref contact group members
                       1 - deref contact group members
                       Note: for performance reason, derefGroupMember is supported
                       only when specific contact ids are specified.

  {returnHiddenAttrs} : whether to return contact hidden attrs defined in zimbraContactHiddenAttributes.
                        ignored if <a> is present.

  {max-members} : number of max GAL group members to return.
                  If number of members on a GAL group is greater than the specified max, 
                  do not return any members under <cn> for the entry.  
                  Instead, return a "tooManyMembers="1" on the <cn>.

  {returnCertInfo} : whether to return the certificate information block for the contact. Default is 0
  {memberOf} : If set, Include the list of contact groups this contact is a member of.
               Note: use sparingly, there is a performance penalty associated with computing this information

<GetContactsResponse>
  <cn [md="{metadata-change-date}"] [tooManyMembers="1"]>...</cn>*
</GetContactsResponse>

Certificate information is returned as <certificate> element
If returnCertInfo is 0, certificate information is not returned
If returnCertInfo is 1, certificate information is returned as shown in the below example -

<GetContactsResponse xmlns="urn:zimbraMail">
  <cn id="680" fileAsStr="group1" d="1308612784000" rev="900" l="7">
    <a n="nickname">group one</a>
    <a n="type">group</a>
    <a n="fileAs">8:group1</a>
    <certificate>...</certificate>
  </cn>
</GetContactsResponse>

Contact group members are returned as <m> elements.
If derefGroupMember is not "1", group members are returned in the ordered they were inserted
in the group.

If derefGroupMember="1", group members are returned in the ordered of "key" of member.
Key is:
    * for contact ref (type="C"): the fileAs field of the Contact
    * for GAL ref (type="G"): email address of the GAL entry
    * for inlined member (type="I"): the value

contact group members are returned as sub-elements of <m>.
If for any(transient or permanent) reason a member cannot be dereferenced, then there will be no sub-element under <m>.

For example:
<GetContactsResponse xmlns="urn:zimbraMail">
  <cn id="680" fileAsStr="group1" d="1308612784000" rev="900" l="7">
    <a n="nickname">group one</a>
    <a n="type">group</a>
    <a n="fileAs">8:group1</a>
    <m value="user@zimbra.com" type="I"/>
    <m value="282" type="C">
      <cn id="282" fileAsStr="Smith, John" d="1308547353000" rev="27" l="7">
        <a n="lastName">Smith</a>
        <a n="email">jsmith@example.zimbra.com</a>
        <a n="workURL">http://www.example.zimbra.com</a>
        <a n="company">Zimbra</a>
        <a n="workCountry">US</a>
        <a n="workState">CA</a>
        <a n="workPhone">(408) 123-4567</a>
        <a n="firstName">Mark</a>
      </cn>
    </m>
    <m value="uid=user1,ou=people,dc=phoebe,dc=mbp" type="G">
      <cn id="2a692f57-1a5b-4542-9f8e-28dfdd0e3f43:260" fileAsStr="Demo User One" d="1308626790000" rev="22" l="257">
        <a n="createTimeStamp">20110620052132Z</a>
        <a n="lastName">user1</a>
        <a n="email">user1@phoebe.mbp</a>
        <a n="zimbraId">b4bf7953-c10f-449e-b7fe-3df48eea36f8</a>
        <a n="objectClass">inetOrgPerson</a>
        <a n="objectClass">zimbraAccount</a>
        <a n="objectClass">amavisAccount</a>
        <a n="fullName">Demo User One</a>
        <a n="dn">uid=user1,ou=people,dc=phoebe,dc=mbp</a>
        <a n="workPhone">+1 650 555 1111</a>
        <a n="modifyTimeStamp">20110620052229Z</a>
        <a n="fileAs">8:Demo User One</a>
      </cn>
    </m>
  </cn>
</GetContactsResponse>

Contact Group membership information is returned as a <memberOf> element which contains a comma separated list
of IDs of contact groups this contact is a member of.
If memberOf is 0, memberOf information is not returned
If memberOf is 1, memberOf information is returned as shown in the below example -

<GetContactsResponse xmlns="urn:zimbraMail">
  <cn fileAsStr="" rev="2" d="1501764925000" id="50074a04-0a5f-4c28-ba93-9b445d9e2c12:257"
                    l="50074a04-0a5f-4c28-ba93-9b445d9e2c12:7">
    <a n="fullName">contactGroupMembership-user2-contact1</a>
    <memberOf>50074a04-0a5f-4c28-ba93-9b445d9e2c12:261,50074a04-0a5f-4c28-ba93-9b445d9e2c12:262</memberOf>
  </cn>
  <cn fileAsStr="" rev="2" d="1501764925000" id="257" l="7">
    <a n="fullName">contactGroupMembership-user1-contact1</a>
    <memberOf>261,260,259</memberOf>
  </cn>
</GetContactsResponse>

----------

<ContactActionRequest>
  <!-- some actions can be preceeded by a "!" to negate them -->
  <action id="{list}" op="move|delete|flag|trash|tag|update" tag="{id}" l="..."/>
</ContactActionRequest>

<ContactActionResponse>
  <action id="{list}" op="move|delete|flag|trash|tag|update"/>
</ContactActionResponse>

  {list} = on input, list of contacts to act on, on output, list of
           contacts that were acted on

for op="update", caller can specify any or all of: l="{folder}", tn="{tag-names}", f="{flags}", color="{color}", <a> attribute list:

  <action id="{list}" op="update" [l="{folder}"] [tn="{tag-names}"] [f="{flags}"] [color="{color}"]>
    [<a n="fieldName">fieldValue</a>]*
  </action>

  See <ItemActionRequest> for more details.

----------

<ImportContactsRequest ct="{content-type}" [l="{folder-id}"] [csvfmt="{csv-format}"] [csvlocale="{csv-locale}"]>
  <content [aid="{attach-upload-id}"]>...</content>
</ImportContactsRequest>

<ImportContactsResponse>
  <cn ids="{list-of-created-ids} n="{num-imported}"/>
</ImportContactsResponse>

{content-type} = only currently supported content type is "csv"
{folder-id} = optional folder id to import contacts into

{attach-upload-id} = attachment id from upload server. If specified, then body of content is ignored.
{csv-format} = the format of csv being imported.  when it's not defined Zimbra
               format is assumed.  the supported formats are defined in
               $ZIMBRA_HOME/conf/zimbra-contact-fields.xml
{csv-locale} = The locale to use when there are multiple {csv-format} locales defined.  When it is not
               specified, the {csv-format} with no locale specification is used.

TODO: should have an option on import that matches email addresses to existing contacts, and updates/ignores them.

----------

<ExportContactsRequest ct="{content-type}" [l="{folder-id}"] [csvfmt="{csv-format}"] [csvlocale="{csv-locale}"] [csvsep="{csv-delimiter}"]/>

<ExportContactsResponse>
  <content>...</content>
</ExportContactsResponse>

{content-type} = currently, the only supported content type is "csv" (comma-separated values)
{folder-id} = optional folder id to export contacts from
{csv-format} = optional csv format for exported contacts.  the supported formats
               are defined in $ZIMBRA_HOME/conf/zimbra-contact-fields.xml
{csv-locale} = The locale to use when there are multiple {csv-format} locales defined.  When it is not
               specified, the {csv-format} with no locale specification is used.
{csv-delimiter} = optional delimiter to use in the resulting csv file

----------

EXAMPLE:

<SearchRequest>
  <query>is:unread</query>
</SearchRequest>

<SearchResponse hits="2" offset="...">
   <c id="12344" n="2" u="1" d="10023420023" tn="foo,tag2" f="1">
     <e p="Roland Schemers" a="schemers@example.zimbra.com" d="Roland"/>
     <e p="Dan Karp" a="dan@example.zimbra.com" d="Dan"/>
     <su>Speaking of animals</su>
     <fr>I am still looking for my monkey!</fr>
   </c>
   <c id="456" n="2" u="1" d="10023420023" tn="tag2,qux" a="1">
     <e p="Roland Schemers" a="schemers@example.zimbra.com" d="Roland"/>
     <e p="Ross Dargahi" a="ross@example.zimbra.com" d="Ross"/>
     <su>phone numbers</su>
     <fr>(650) 123-4567</fr>
   </c>
 </SearchResponse>

 EXAMPLE:

<GetConvRequest>
 <c id="12345">
   <m id=""9845"/>
 </c>
</GetConvRequest>

<GetConvResponse>
  <c id="12345" tn="foo,tag2" n="2">
   <su>Speaking of animals</su>
   <m id="123445" f="1" s="1234" d="10002323">
     <e p="Dan Karp" a="dan@example.zimbra.com"/>
     <fr>This is the fragment</fr>
   </m>
   <m id="9845" a="1" s="128981" d="10002323">
     <e t="f" p="Roland Schemers" a="schemers@example.zimbra.com"/>
     <e t="t" p="Dan Karp" a="dan@example.zimbra.com"/>
     <fr>This is another frag</fr>
     <mp part="" ct="multipart/mixed">
       <mp part="1" ct="text/plain" body=1">
         <content>This is another frag that is part of a bigger
message. blah blah blah</content>
       </mp>
       <mp part="2" ct="message/rfc822">
         <mp part="2.1" ct="multipart/mixed">
           <mp part="2.1.1" ct="text/plain" name="README.txt" cd="attachment" filename="README.txt"/>
           <mp part="2.1.2" ct="image/jpeg" name="shot1.jpg" cd="inline" filename="shot1.jpg"/>
         </mp>
       </mp>
     </mp>
   </m>
  </c>
</GetConvResponse>

EXAMPLE:

<GetMsgRequest>
 <m id="9845"/>
</GetMsgRequest>

<GetMsgResponse>
   <m id="9845" a="1" s="128981" d="10002323">
     <e t="f" id="1" p="Roland Schemers" a="schemers@example.zimbra.com"/>
     <e t="t" id="2" p="Dan Karp" a="dan@example.zimbra.com"/>
     <su>Speaking of animals</su>
     <fr>This is another frag</fr>
     <mp part="" ct="multipart/mixed"/>
       <mp part="1" ct="text/plain" body="1"/>
        <content>This is another frag that is part of a bigger
message. blah blah blah</content>
       </mp>
       <mp part="2" ct="message/rfc822"/>
         <mp part="2.1" ct="multipart/mixed"/>
           <mp part="2.1.1" ct="text/plain"/>
           <mp part="2.1.2" ct="text/plain" name="README.txt" cd="attachment" filename="README.txt"/>
           <mp part="2.1.3" ct="image/jpeg" name="shot1.jpg" cd="inline" filename="shot1.jpg"/>
         </mp>
       </mp>
     </mp>
   </m>
</GetMsgResponse>

EXAMPLE:

<mail:BrowseRequest xmlns:mail="urn:zimbraMail">
   <query>from:roland</query>
   <browseBy>attachments</browseBy>
</mail:BrowseRequest>

<mail:BrowseResponse xmlns:mail="urn:zimbraMail">
  <bd>application/pdf</bd>
  <bd>application/msword</bd>
  <bd>application/vnd.ms-powerpoint</bd>
  <bd>image/jpeg</bd>
  <bd>application/octet-stream</bd>
  <bd>text/plain</bd>
  <bd>image/gif</bd>
  <bd>message/rfc822</bd>
</mail:BrowseResponse>

-----------------------

 <NoOpRequest [wait='1' [delegate='0']] [limitToOneBlocked='1'] [timeout="msecs to wait"]/>

 <NoOpResponse [waitDisallowed="1"]/>

A request that does nothing and always returns nothing. Used to keep a session alive, and return
any pending notifications.

If "wait" is set, and if the current session allows them, this request
will block until there are new notifications for the client.  Note
that the soap envelope must reference an existing session that has
notifications enabled, and the notification sequencing number should
be specified.

If "wait" is set, the caller can specify whether notifications on
delegate sessions will cause the operation to return.  If "delegate"
is 0, delegate mailbox notifications will be ignored.  The default is 1.

Some clients (notably browsers) have a global-limit on the number of
outstanding sockets...in situations with two App Instances connected
to one Zimbra Server, the browser app my appear to 'hang' if two app
sessions attempt to do a blocking-NoOp simultaneously.  Since the apps
are completely separate in the browser, it is impossible for the apps
to coordinate with each other -- therefore the 'limitToOneBlocked'
setting is exposed by the server.  If specified, the server will only
allow a given user to have one single waiting-NoOp on the server at a
time, it will complete (with waitDisallowed='1') any existing
limited hanging NoOpRequests when a new request comes in.

The server may reply with a "waitDisallowed" attribute on response to
a request with wait="1".  If "waitDisallowed" is true, then
blocking-NoOpRequests (ie requests with wait="1") are *not* allowed by
the server right now, and the client should stop attempting them.

The client may specifiy a custom timeout-length for their request if
they know something about the particular underlying network.  The
server may or may not honor this request (depending on server
configured max/min values: see Server attributes
zimbraMailboxNoopDefaultTimeout, zimbraMailboxNoopMinTimeout and
zimbraMailboxNoopMaxTimeout)

-----------------------

 <SetCustomMetadataRequest id="{item-id}">
   <meta section="{metadata-section-key}">
     (<a n="{key}"> {value} </a>)*
   </meta>
 </SetCustomMetadataRequest>

 <SetCustomMetadataResponse id="{item-id}"/>

    -- setting a custom metadata section but providing no key/value pairs
       will remove the sction from the item


 <GetCustomMetadataRequest id="{item-id}">
   <meta section="{metadata-section-key}"/>
 </GetCustomMetadataRequest>

 <GetCustomMetadataResponse id="{item-id}">
   [<meta section="{metadata-section-key}">
      (<a n="{key}"> {value} </a>)*
    </meta>]
 </GetCustomMetadataResponse>

---------------------------

<SetMailboxMetadataRequest>
  <meta section="{metadata-section-key}">
    (<a n="{key}">{value}</a>)*
  </meta>
</SetMailboxMetadataRequest>

<SetMailboxMetadataResponse/>

    -- setting a mailbox metadata section but providing no key/value pairs
       will remove the section from mailbox metadata
    -- empty value not allowed
    -- {metadata-section-key} must be no more than 36 characters long and must be
       in the format of {namespace}:{section-name}.  currently the only valid
       namespace is "zwc".

<ModifyMailboxMetadataRequest>
  <meta section="{metadata-section-key}">
    (<a n="{key}">{value}</a>)+
  </meta>
</ModifyMailboxMetadataRequest>

<ModifyMailboxMetadataResponse/>

    -- modify request must contain one or more key/value pairs
    -- existing keys' values will be replaced by new values
       empty or null value will remove a key
    -- new keys can be added

<GetMailboxMetadataRequest>
  <meta section="{metadata-section-key}"/>
</GetMailboxMetadataRequest>

<GetMailboxMetadataResponse>
  <meta section="{metadata-section-key}">
     (<a n="{key}">{value}</a>)*
  </meta>
</GetMailboxMetadataResponse>

---------------------------

<GetRulesRequest>
<SaveRulesRequest>

These APIs have been replaced with <GetFilterRulesRequest> and <ModifyFilterRulesRequest>, which offer improved ease of
use and error handling.  The old APIs still work in ZCS 6.0, but have been removed since ZCS 8.0.

---------------------------

<GetFilterRulesRequest/>

<GetFilterRulesResponse>
  <filterRules>
    <filterRule name="{rule-name}" [active="{0|1}"]>*
        <filterVariables>
            <filterVariable name="{variable-name}" value="{variable-value}"/>
            ...
        </filterVariables>
        <filterTests [condition="{allof | anyof"}]>
        {test}
        [test]
        ...
      </filterTests>
      [<nestedRule>
        <filterTests>...</filterTests>
        [<nestedRule>...</nestedRule>]
        [<filterActions>...</filterActions>]
      </nestedRule>]
      [<filterActions>
        <filterVariables>
            <filterVariable name="{variable-name}" value="{variable-value}"/>
            ...
        </filterVariables>
        {action}
        [action]
        ...
      </filterActions>]
    </filterRule>
  </filterRules>
</GetFilterRulesResponse>


<ModifyFilterRulesRequest>
  <filterRules> ... </filterRules>
</ModifyFilterRulesRequest>

<ModifyFilterRulesResponse/>

    * Default value for "active" is 1.
    * Default value for "condition" is "allof"

Tests:

  <addressBookTest header="{header-name}"/>
  <addressTest [part="{all|localpart|domain}"] stringComparison="{type}" [caseSensitive="{0|1}"]
      header="{comma-separated-header-names}" value="{value}"/>
  <addressTest [part="{all|localpart|domain}"] valueComparison="{gt|ge|lt|le|eq|ne}" [valueComparisonComparator="{i;ascii-numeric|i;ascii-casemap|i;octet}"] [caseSensitive="{0|1}"]
      header="{comma-separated-header-names}" value="{value}"/>
  <addressTest [part="{all|localpart|domain}"] countComparison="{gt|ge|lt|le|eq|ne}"
      header="{comma-separated-header-names}" value="{value}"/>
  <envelopeTest [part="{all|localpart|domain}"] stringComparison="{type}" [caseSensitive="{0|1}"]
      header="{comma-separated-header-names}" value="{value}"/>
  <envelopeTest [part="{all|localpart|domain}"] valueComparison="{gt|ge|lt|le|eq|ne}" [valueComparisonComparator="{i;ascii-numeric|i;ascii-casemap|i;octet}"] [caseSensitive="{0|1}"]
      header="{comma-separated-header-names}" value="{value}"/>
  <envelopeTest [part="{all|localpart|domain}"] countComparison="{gt|ge|lt|le|eq|ne}"
      header="{comma-separated-header-names}" value="{value}"/>
  <attachmentTest/>
  <bulkTest/>
  <contactRankingTest header="{header-name}"/>
  <conversationTest [where="{started|participated}"]/>
  <currentDayOfWeekTest value="comma-separated-day-of-week-indices"/>
  <currentTimeTest dateComparison="{before|after}" d="time-in-HHmm-format}"/>
  <bodyTest [caseSensitive="{0|1}"] value="{value}"/>
  <dateTest dateComparison="{before|after}" d="{date}"/>
  <facebookTest/>
  <flaggedTest flagName="{flagged|read|priority}"/>
  <headerExistsTest header="{header-name}"/>
  <headerTest header="{comma-separated-header-names}" stringComparison="{type}" [caseSensitive="{0|1}"] value="{value}"/>
  <headerTest header="{comma-separated-header-names}" valueComparison="{gt|ge|lt|le|eq|ne}" [valueComparisonComparator="{i;ascii-numeric|i;ascii-casemap|i;octet}"] [caseSensitive="{0|1}"] value="{value}"/>
  <headerTest header="{comma-separated-header-names}" countComparison="{gt|ge|lt|le|eq|ne}" value="{value}"/>
  <importanceTest imp="{high|normal|low}"/>
  <inviteTest>
    <method>{method}</method>+
  </inviteTest>
  <linkedinTest/>
  <listTest/>
  <meTest header="{header-name}"/>
  <mimeHeaderTest header="{header-name}" stringComparison="{type}" [caseSensitive="{0|1}"] value="{value}"/>
  <sizeTest numberComparison="{over|under}" s="{size}"/>
  <socialcastTest/>
  <twitterTest/>
  <communityRequestsTest/>
  <communityContentTest/>
  <communityConnectionsTest/>

Each test has the following optional attributes:
    * "negative": specifies a "not" condition for that test
    * "index": specifies a guaranteed order for the test and action elements

Actions:

  <filterVariables>
    <filterVariable name="{variable-name}" value="{variable-value}"/>
    ...
  </filterVariables>
  <actionKeep />
  <actionDiscard />
  <actionFileInto folderPath="{folder-path}" [copy="{0|1}"]/>
  <actionTag tagName="{tag-name}" />
  <actionFlag flagName="{flagged|read|priority}" />
  <actionRedirect a="{email-address}" [copy="{0|1}"]/>
  <actionStop />
  <actionReply>
    <content>{body-template}</content>
  </actionReply>
  <actionNotify a="email-address" [su="subject-template"] [maxBodySize="{num-bytes}"] [origHeaders="{comma-separated-header-names}|*"]>
    <content>{body-template}</content> ?
  </actionNotify>
  <actionRFCCompliantNotify from="{from}" [importance="{importance}"] [options="{options}"] message="{subject}">
    <method>{method}</method>
  </actionRFCCompliantNotify>
  <actionReject [index={"index-number"}]>{this is reject message}</actionReject>
  <actionEreject [index={"index-number"}]>{this is ereject message}</actionEreject>
  <actionLog [level={fatal|error|warn|info|debug|trace}] [index={"index-number"}]>{this is log message}</actionLog>

Each action has an optional "index" attribute which specifies a guaranteed order
for the action elements.

stringComparison values: is, contains, matches
numberComparison values: over, under
dateComparison values: before, after
size values are in bytes (no suffix), kilobytes (50K), megabytes (50M) or gigabytes (2G)
<dateTest>: date values are are truncated to the day. Hours, minutes, and seconds are ignored.
index is an integer, used to maintain the order of filter tests and actions.
method values: anyrequest, anyreply, publish, request, reply, add, cancel, refresh,
  counter, declinecounter.  anyrequest matches publish, request, add, cancel,
  declinecounter.  anyreply matches reply, refresh, counter.  If no methods are
  specified, the test returns true for all invites.
<mimeHeaderTest>: behaves just like <headerTest>, but matches headers on
  all MIME parts, instead of just the top-level headers.
<currentDayOfWeekTest>: day-of-week-indices - 0=Sunday, 6=Saturday
body-template/subject-template: Can contain variables such as ${SUBJECT}, ${TO}, ${CC}, etc
  (basically ${any-header-name}; case not important), plus ${BODY} (text body of the message).
origHeaders: Specifies list of headers to be copied from the original message to the notification message.
  Value "*" implies that all headers need to be copied.
<addressTest>: this test is preferred instead of <headerTest> for headers that contain email addresses. The default
  value of the part attribute is "all" which implies comparison against the full email address.
<communityRequestsTest>, <communityContentTest>, and <communityConnectionsTest> all check the "X-Zimbra-Community-Notification-Type"
header against predefined groups of values. The groups are:

communityRequestsTest:
bb196c30-fad3-4ad8-a644-2a0187fc5617 - Friendships Requests
3772ef23-6aa0-4a22-9e88-a4313c37ebe6 - Group Membership Request
1b0500d2-c789-421e-a25b-3ab823af53be - Forums Requiring Moderation

communityContentTest:
6a3659db-dec2-477f-981c-ada53603ccbb - Likes
94dc0d37-3a65-43de-915d-d7d62774b576 - Ratings
4876d7ce-b48c-4a08-8cd9-872342c5bdf8 - Blog Post Comment
82e1d0b4-854e-43c9-85d7-dea7d4dec949 - Wiki Page Update
8e627c29-8602-4110-877d-0232e4ea2fd5 - Media Comment
be997a7a-5026-435f-8ea5-4fe3d90a6ba9 - New Media in Owned Gallery
eea4ccbb-6e07-4a6d-9bb6-8b02f060f79c - Forum Thread Awaiting Moderation Notification
352a702d-2a77-4307-9e9e-c564426e8cc8 - Forum Thread Subscription Notification
0e952633-fa46-448d-b1aa-bb6c60a388fb - Forum Reply Awaiting Moderation Notification
e3df1b21-ac81-4eb3-8ab6-69dc049f5684 - Forum Replies
f8c93cd5-d40e-461d-b13a-b02e92bfcbbf - Forum Thread Verified Answers

communityConnectionsTest:
194d3363-f5a8-43b4-a1bd-92a95f6dd76b - Friendships
1cee0f92-3650-4110-9f0b-69b0e175914d - Mentions
bb196c30-fad3-4ad8-a644-2a0187fc5617 - Group Membership
328e5139-d759-405c-98da-91cd25bcc80c - Group Mentions

Nested Rules:

In addition to the normal set of tests and actions, a filter rule may contain one or more layers of nested rules. If nested rules are
specified the filter action(s) must be specified on the innermost level. All conditions are evaluated and if true the innermost action(s) are executed.
Note that as of ZCS 8.5 nested filter rules are supported in the SOAP API but not in the end user filter preferences UI.

Notify action:
<actionNotify> generates the Zimbra specific format of the notify filter rule.
<actionRFCCompliantNotify> generates the RFC 5436 and 5436 compliant notify filter rule.
<actionRFCCompliantNotify> is available only when the global config 'zimbraMailSieveNotifyActionRFCCompliant' key is set to TRUE 
(if this key is set to TRUE, the Zimbra-format notify action will fail to execute, and vise versa).
  {from} : The from address which is displayed at the From header of the notification message.
  {subject} : The subject of the notification message.
  {method} : "mailto:" url.  Please refer to the RFC 5436 for more details.
  {importance} and {options} : Reserved.
---------------------------

<ApplyFilterRulesRequest>
  <filterRules>
    <filterRule name="{name}"/>+
  </filterRules>
  [<m ids="{msg-id-list}"/>]
  [<query>{query-string}</query>]
</ApplyFilterRulesRequest>

<ApplyFilterRulesResponse>
  <m ids="{msg-id-list}"/>
</ApplyFilterRulesResponse>

Applies one or more filter rules to messages specified by a comma-
separated ID list, or returned by a search query.  One or the other
can be specified, but not both.  Returns the list of ids of
existing messages that were affected.

Note that redirect actions are ignored when applying filter rules
to existing messages.

--------------------------

Corresponding API for outgoing/sent email filters (message structure same as above):

<GetOutgoingFilterRulesRequest/>

<GetOutgoingFilterRulesResponse>
  ...
</GetOutgoingFilterRulesResponse>


<ModifyOutgoingFilterRulesRequest>
  ...
</ModifyOutgoingFilterRulesRequest>

<ModifyOutgoingFilterRulesResponse/>


<ApplyOutgoingFilterRulesRequest>
  ...
</ApplyOutgoingFilterRulesRequest>

<ApplyOutgoingFilterRulesResponse>
  ...
</ApplyOutgoingFilterRulesResponse>

--------------------------

Synchronization:

   *** PLEASE SEE sync.txt FOR SYNC-RELATED DOCUMENTATION ***

---------------------------

<GetSpellDictionariesRequest>

<GetSpellDictionariesResponse>
  <dictionary>en_US</dictionary>
  ...
</GetSpellDictionariesResponse>

Returns the list of dictionaries that can be used for spell
checking.

---------------------------

<CheckSpellingRequest [dictionary="{name}"] [ignore="{words}"]>
    [text to spell check]
</CheckSpellingRequest>

<CheckSpellingResponse available="0|1">
  <misspelled word="chickun" suggestions="chicken,chocking,chucking,Chicky,checking"/>
</CheckSpellingResponse>

Suggested words are listed in decreasing order of their match score.
The "available" attribute specifies whether the server-side spell checking
interface is available or not.

{name} : the optional name of the aspell dictionary that will be used to
check spelling.  If not specified, the the dictionary will be either
zimbraPrefSpellDictionary or the account's locale, in that order.

{words} : comma-separated list of words to ignore just for this request.
These words are added to the user's personal dictionary of ignore words
stored as zimbraPrefSpellIgnoreWord.

---------------------------

<GetAllLocalesRequest/>

<GetAllLocalesResponse>
  <locale id="en_US" name="English (United States)" localName="English (United States)"/>
  ...
</GetAllLocalesResponse>

name: name in the locale itself
localName: name in the user's locale

Returns all locales defined in the system.  This is the same list returned by
java.util.Locale.getAvailableLocales(), sorted by display name (name attribute).

---------------------------

<GetAvailableLocalesRequest/>

<GetAvailableLocalesResponse>
  <locale id="{locale-id}" name="{locale-name-in-preferred-locale}"/>
  ...
</GetAvailableLocalesResponse>

Returns intersection of all translated locales installed on the server and the list specified in zimbraAvailableLocale.
The locale list in the response is sorted by display name (name attribute).

{locale-id} : locale id. e.g. en_US
{locale-name-in-preferred-locale} : locale name in the preferred locale
                For example, if the locale is fr_CA and the preferred locale is en_US, name will contain "French (Canada)";
                if the locale is en_US and the preferred locale is fr_CA, name will contain "anglais (Etats-Unis)"

                The preferred locale is determined with the following precedence:
                (1) zimbraPrefLocale of the target account if it is present
                (2) Otherwise the locale specified in the Accept-Language http header if it is present
                (3) Otherwise the locale returned by Provisioning.getLocale, which uses a predefined fallback
                    chain to determine the preferable locale.


---------------------------

<TestDataSourceRequest>
  <pop3 host="pop.myisp.com" port="110" connectionType="cleartext|ssl"
    username="mylogin" password="mypassword" leaveOnServer="true|false"
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]/>

  or

  <imap host="imap.myisp.com" port="143" connectionType="cleartext|ssl"
    username="mylogin" [password="mypassword"] [oauthToken="myOAuthToken"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]/>
</TestDataSourceRequest>

or

<TestDataSourceRequest>
  <pop3 id="{id}" [host="pop.myisp.com"] [port="110"] [connectionType="cleartext|ssl"]
    [username="mylogin"] [password="mypassword"]/>

  or

  <imap id="{id}" [host="imap.myisp.com"] [port="143"] [connectionType="cleartext|ssl"]
    [username="mylogin"] [password="mypassword"] [oauthToken="myOAuthToken"]/>
</TestDataSourceRequest>

<TestDataSourceResponse>
   <pop3 success="0|1" [error="Error message"]/>

   or

   <imap success="0|1" [error="Error message"]/>
</TestDataSourceResponse>

Tests the connection to the specified data source.  Does not modify
the data source or import data.  If the id is specified, uses an existing
data source.  Any values specified in the request are used in the test
instead of the saved values.

---------------------------

===================
emailAddress="changed-phoebe@google.com"
                    useAddressForForwardReply="false"
                    defaultSignature="95915d7a-1809-4a73-a50f-c465214fae62"
                    fromDisplay="changed-from-display"
                    replyToAddress="changed-replay-to-addr@google.com"
                    replyToDisplay="changed-replyto-display"/>
==================
<CreateDataSourceRequest/>
  <pop3 name="My POP3 Account" isEnabled="0|1" host="pop.myisp.com" port="110"
    connectionType="cleartext|ssl" username="mylogin" password="mypassword" l="{folder-id}"
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    leaveOnServer="0|1" [pollingInterval="10m"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [forwardReplySignature="{forward-reply-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]/>

  or

  <imap name="My IMAP Account" isEnabled="0|1" host="imap.myisp.com" port="143" connectionType="cleartext|ssl"
    username="mylogin" [password="mypassword"] l="{folder-id}"
    [oauthToken="myOAuthToken" clientId="clientId" clientSecret="clientSecret"
    refreshToken="refreshToken" refreshTokenUrl="refreshTokenUrl"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    [pollingInterval="10m"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]
    [test="0|1"]/>
</CreateDataSourceRequest>

<CreateDataSourceResponse>
  <pop3 id="{id}"/>
</CreateDataSourceResponse>

Creates a data source that imports mail items into the specified folder via
the POP3 or IMAP protocol.  Only one data source is allowed per request.

If SMTP is being enabled for the mail data source (IMAP/POP3) and SMTP settings are being specified, the
emailAddress attr must also be specified.

---------------------------

<GetDataSourcesRequest/>

<GetDataSourcesResponse>
  *[<pop3 id="{id}" name="My POP3 Account" isEnabled="0|1" host="pop3.myisp.com" port="110"
    username="mylogin" l="{folder-id}" leaveOnServer="0|1" [pollingInterval="10m"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [forwardReplySignature="{forward-reply-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]
    [failingSince="{timestamp}">]
    [<lastError>{error message}</lastError>]
   </pop3>]
  *[<imap name="My IMAP Account" isEnabled="0|1" host="imap.myisp.com" port="143"
    connectionType="cleartext|ssl" username="mylogin" l="{folder-id}" [pollingInterval="10m"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [forwardReplySignature="{forward-reply-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]>
    [failingSince="{timestamp}">]
    [<lastError>{error message}</lastError>]
   </imap>]
  ...
</GetDataSourcesResponse>

Returns all data sources defined for the given mailbox.  For each data source,
every attribute value is returned except password.

lastError: the error message from the most recent sync for this data source.
  This element is not returned if the last sync was successful.
failingSince: if the most recent sync(s) failed, this attribute specifies
  the timestamp of the first failure.  This attribute is not returned
  if the last sync was successful.
  
--------------------------
Note: OAuthToken is temporary and it expires after a certain time interval
Client can refresh the OAuthToken in two ways
1. Refresh and update OAuthToken periodically
2. Refresh and update OAuthToken if the client gets the response as - error=" Invalid credentials (Failure)"
---------------------------

---------------------------

<ModifyDataSourceRequest>
  *[<pop3 id="{id}" [name="My POP3 Account"] [isEnabled="0|1"] [host="pop3.myisp.com"]
    [port="110"] [connectionType="cleartext|ssl"] [username="mylogin"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    [password="mypassword"] [l="{folder-id}"] [leaveOnServer="0|1"]
    [pollingInterval="10m"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [forwardReplySignature="{forward-reply-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]/>
  *[<imap name="My IMAP Account" isEnabled="0|1" host="imap.myisp.com" port="143" connectionType="cleartext|ssl"
    username="mylogin" [password="mypassword"] l="{folder-id}"
    [oauthToken="myOAuthToken" clientId="clientId" clientSecret="clientSecret"
    refreshToken="refreshToken" refreshTokenUrl="refreshTokenUrl"]
    [smtpEnabled="0|1" smtpHost="smtp.myisp.com" smtpPort="465" smtpConnectionType="cleartext|ssl"
    smtpAuthRequired="0|1" smtpUsername="mylogin" smtpPassword="mypassword"]
    [pollingInterval="10m"]
    [emailAddress="{email-address}"]
    [useAddressForForwardReply="0|1"]
    [defaultSignature="{default-signature-id}"]
    [forwardReplySignature="{forward-reply-signature-id}"]
    [fromDisplay="{from-display}"]
    [replyToAddress="{replyto-address}"]
    [replyToDisplay="{replyto-display}"]
    [test="0|1"]/>
</ModifyDataSourceRequest>

<ModifyDataSourceResponse/>

Changes attributes of the given data source.  Only the attributes specified in the request
are modified.  If the username, host or leaveOnServer settings are modified, the server
wipes out saved state for this data source.  As a result, any previously downloaded
messages that are still stored on the remote server will be downloaded again.

---------------------------

<DeleteDataSourceRequest>
  *[<dsrc [id="{data-source-id}" | name="{data-source-name}"]/>]
  *[<pop3 [id="{data-source-id}" | name="{data-source-name}"]/>]
  *[<imap [id="{data-source-id}" | name="{data-source-name}"]/>]
  ...
</DeleteDataSourceRequest>

<DeleteDataSourceResponse/>

Deletes the given data sources.  The name or id of each data source must
be specified.

---------------------------

<ImportDataRequest>
  *[<dsrc id="{id}"/>]
  *[<pop3 id="{id}"/>]
  *[<imap id="{id}"/>]
  ...
</ImportDataRequest>

<ImportDataResponse/>

Triggers the specified data sources to kick off their import processes.  Data import runs
asynchronously, so the response immediately returns.  Status of an import can be queried
via the <GetImportStatusRequest> message.  If the server receives an
<ImportDataRequest> while an import is already running for a given data source,
the second request is ignored.

---------------------------

<GetImportStatusRequest/>

<GetImportStatusResponse>
  *[<pop3 id="{id}" isRunning="0|1" [success="0|1"] [error="Error message"]/>]
  *[<imap id="{id}" isRunning="0|1" [success="0|1"] [error="Error message"]/>]
  ...
</GetImportStatusResponse>

Returns current status for all data sources.  Status values for a data source are
reinitialized when either (a) another import process is started or (b) when the
server is restarted.  If import has not run yet, the success and error attributes
are not specified.

isRunning: Whether data is currently being imported from this data source.
success:   Whether the last import completed successfully.
error:     If the last import failed, the error message that was returned.

---------------------------

WaitSet: scalable mechanism for listening for changes to one or more accounts

<CreateWaitSetRequest>
<CreateWaitSetResponse>
<WaitSetRequest>
<WaitSetResponse>
<DestroyWaitSet>
<DestroyWaitSetResponse>

***See soap-waitset.txt for WaitSet API documentation***

---------------------------

Get account level permissions.

Note: to be deprecated in Zimbra 9.  Use zimbraAccount GetRights instead.

<GetPermissionRequest>
   <!-- get only the permissions for the specified rights -->
   [<ace right="{right1}"/>
    <ace right="{right2}"/>]
</GetPermissionRequest>

If no <ace> elements are provided, all ACEs are returned in the response.
If <ace> elements are provided, only those ACEs with specified rights are returned in the response.

<GetPermissionResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</GetPermissionResponse>

    {right}        = viewFreeBusy | invite

    {deny}         = 1 | 0(default)
                     if a right is specifically denied

    {grantee-type} = the type of grantee:
                     usr - Zimbra user
                     grp - Zimbra group(distribution list)
                     all - all authenticated users
                     gst - non-Zimbra email address and password (not yet supported)
                     key - external user with an accesskey
                     pub - public authenticated and unauthenticated access

    {zimbra-id}    = zimbraId of the grantee

    {grantee-name} = name or email address of the grantee.
                     ot present if {grantee-type} is "all" or "pub"

    {pw}           = optional arguments.  password when {grantee-type} is "gst" (not yet supported)

    {key}          = optional arguments.  access key when {grantee-type} is "key"

---------------------------

Grant account level permissions.

Note: to be deprecated in Zimbra 9.  Use zimbraAccount GrantRights instead.

<GrantPermissionRequest>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" [zid="{zimbra-id}"] [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>+
</GrantPermissionRequest>

  If gt is:
     usr - either zid or d is required.
     grp - either zid or d is required.
     all - zid, d, pw are ignored
     gst - zid is ignored, d is required, pw is optional
     key - zid is ignored, d is required
     pub - zid, d, pw are ignored

  For usr and grp:
     - if zid is provided, server will lookup the entry by zid and grantee type, and d is ignored.
     - if zid is not provided and d is provided, server will lookup the grantee by name and grantee type.
     if the lookup failed, NO_SUCH_ACCOUNT/NO_SUCH_DISTRIBUTION_LIST will be thrown.

  If gt == key:
     - if key is given, server will use that as the access key for this grant
     - if key is not given, server will generate an access key


GrantPermissionResponse returns permissions that are successfully granted.

<GrantPermissionResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</GrantPermissionResponse>
---------------------------

Revoke account level permissions.

Note: to be deprecated in Zimbra 9.  Use zimbraAccount RevokeRights instead.

<RevokePermissionRequest>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" [zid="{zimbra-id}"] [d="{grantee-name}"]/>*
</RevokePermissionRequest>

  Same notes as those for GrantPermissionRequest about identifying the grantee.

RevokePermissionResponse returns permissions that are successfully revoked.

<RevokePermissionResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</RevokePermissionResponse>

---------------------------

Note: to be deprecated in Zimbra 9.  Use zimbraAccount CheckRights instead.

<CheckPermissionRequest>
  <target type="{target-type}" by="id|name">...</target>
  <right>...</right>+
</CheckPermissionRequest>

{target-type} = account | calresource | dl

    Check if the authed user has the specified right(s) on a target.

    If the specified target cannot be found:
    - if by is "id", throw NO_SUCH_ACCOUNT/NO_SUCH_CALENDAR_RESOURCE
    - if by is "name", return the default permission for the right.

e.g.
With user1's auth token, the following checks if user1 can invite user2 and
view user2's free/busy.

<CheckPermissionRequest>
  <target type="account" by="name">user2@test.com</target>
  <right>invite</right>
  <right>viewFreeBusy</right>
</CheckPermissionRequest>


<CheckPermissionResponse allow="{1|0}">
  <right allow="{1|0}">invite</right>
  <right allow="{1|0}">viewFreeBusy</right>
</CheckPermissionResponse>

allow = 1 | 0
        1: the authed user has the right on the target
        0: the authed user does not have the right on the target
        In CheckPermissionResponse, it is the AND result of each individual result
        In each <right> element, it is the result for that right.


---------------------------

Get account level rights.

<GetRightsRequest>
   <!-- get only grants for the specified rights -->
   [<ace right="{right1}"/>
    <ace right="{right2}"/>]
</GetRightsRequest>

If no <ace> elements are provided, all ACEs are returned in the response.
If <ace> elements are provided, only those ACEs with specified rights are returned in the response.

<GetRightsResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</GetRightsResponse>

    {right}        = viewFreeBusy | invite

    {deny}         = 1 | 0(default)
                     if a right is specifically denied

    {grantee-type} = the type of grantee:
                     usr - Zimbra user
                     grp - Zimbra group(distribution list)
                     all - all authenticated users
                     gst - non-Zimbra email address and password (not yet supported)
                     key - external user with an accesskey
                     pub - public authenticated and unauthenticated access

    {zimbra-id}    = zimbraId of the grantee

    {grantee-name} = name or email address of the grantee.
                     ot present if {grantee-type} is "all" or "pub"

    {pw}           = optional arguments.  password when {grantee-type} is "gst" (not yet supported)

    {key}          = optional arguments.  access key when {grantee-type} is "key"

---------------------------

Grant account level rights.

<GrantRightsRequest>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" [zid="{zimbra-id}"] [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"] [chkgt="{checkGranteeType}"]/>+
</GrantRightsRequest>

  If gt is:
     usr - either zid or d is required.
     grp - either zid or d is required.
     all - zid, d, pw are ignored
     gst - zid is ignored, d is required, pw is optional
     key - zid is ignored, d is required
     pub - zid, d, pw are ignored

  For usr and grp:
     - if zid is provided, server will lookup the entry by zid and grantee type, and d is ignored.
     - if zid is not provided and d is provided, server will lookup the grantee by name and grantee type.
     if the lookup failed, NO_SUCH_ACCOUNT/NO_SUCH_DISTRIBUTION_LIST will be thrown.

  If gt == key:
     - if key is given, server will use that as the access key for this grant
     - if key is not given, server will generate an access key

  If chkgt is set, INVALID_REQUEST will be thrown if wrong grantee type is specified.

GrantRightsResponse returns rights that are successfully granted.

<GrantRightsResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</GrantRightsResponse>
---------------------------

Revoke account level rights.

<RevokeRightsRequest>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" [zid="{zimbra-id}"] [d="{grantee-name}"]/>*
</RevokeRightsRequest>

  Same notes as those for GrantRightsRequest about identifying the grantee.

RevokeRightsResponse returns rights that are successfully revoked.

<RevokeRightsResponse>
  <ace right="{right}" [deny="{deny}"] gt="{grantee-type}" zid="{zimbra-id}" [d="{grantee-name}"] [pw="{password}"] [key="{accesskey}"]/>*
</RevokeRightsResponse>

---------------------------

<DiscoverRightsRequest>
    <right>...</right>+
</DiscoverRightsRequest>

Return all targets of the specified rights applicable to the requested account.
Notes: 
  1. This call only discovers grants granted on the designated target type of the specified rights.  
     It does not return grants granted on target types the rights can inherit from.
     
  2. For sendAs, sendOnBehalgOf, sendAsDistList, sendOnBehalgOfDistList rights,
     name attribute is not returned on <target> elements.  Instead, addresses 
     in the target entry's zimbraPrefAllowAddressForDelegatedSender are returned in   
     <e a="{email-address}"/> elements under the <target> element.  
     If zimbraPrefAllowAddressForDelegatedSender is not set on the target entry, the entry's 
     primary email address will be return in the only <e a="{email-address}"/> element 
     under the <target> element.
     
  3. For all other rights, name attribute is always returned on <target> elements, no 
     <e a="{email-address}"/> will be returned.  name attribute contains the entry's 
     primary name.
      

<DiscoverRightsResponse>
    <targets right="...">
        [<target type="{target-type}" id="..." [name="..."] [d=".."]>
             [<email addr="{email-address}"/>+]
         </target>+]
    </targets>+
</DiscoverRightsResponse>

If a discoverd target is an account or a group, display name of the entry is return in the d="..." 
attribute if the entry has a display name set.

e.g. 
<DiscoverRightsRequest>
    <right>sendAs</right>
    <right>sendAsDistList</right>
    <right>viewFreeBusy</right>
</DiscoverRightsRequest>

<DiscoverRightsResponse>
    <targets right="sendAs">
        <target type="account" id="...">
            <e a="user-one@test.com"/>
            <e a="user.one@test.com"/>
        </target>    
        <target type="account" id="...">
            <e a="user2@test.com"/>
        </target>
    </targets>
    <targets right="sendAsDistList">
        <target type="dl" id="...">
            <e a="group1@test.com"/>
            <e a="group-one@test.com"/>
        </target>
        <target type="dl" id="...">
            <e a="group2@test.com"/>
            <e a="group-two@test.com"/>
        </target>
    </targets>
    <targets right="viewFreeBusy">
        <target type="account" id="..." name="user1@test.com">
    </targets>    
</DiscoverRightsResponse>

---------------------------

<CheckRightsRequest>
  <target type="{target-type}" by="id|name" key="{key}">
    <right>...</right>+
  </target>+
</CheckRightsRequest>

Check if the authed user has the specified right(s) on a target.

{key} = if by id, zimbraId of the target entry
        if by name, name of the target entry
{target-type} = account | calresource | dl | domain


<CheckRightsResponse>
  <target type="{target-type}" by="id|name" key="{key}" allow="{1|0}">
    <right allow="{1|0}">...</right>+
  </target>+
</CheckRightsResponse>

allow = 1 | 0
        1: the authed user has the right on the target
        0: the authed user does not have the right on the target
        For the allow="1|0" on each <target>, it is the AND value of all requetsed rights 
        for the target.



        
---------------------------

<GetVersionInfoRequest/>

<GetVersionInfoResponse>
  <info version="{version-string}" release="{release-string}" buildDate="{YYYYMMDD-hhmm}" buildHost="{host-name}"/>
</GetVersionInfoResponse>

This request will return a SOAP fault if the zimbraSoapExposeVersion
server/globalconfig attribute is set to FALSE.

---------------------------

<GetWhiteBlackListRequest/>

<GetWhiteBlackListResponse>
    <whiteList>
        <addr>...</addr>+
    </whiteList>
    <blackList>
        <addr>...</addr>+
    </blackList>
</GetWhiteBlackListResponse>

----------------------------

<ModifyWhiteBlackListRequest>
    [<whiteList>
        <addr [op="{op}"]>...</addr>+
    </whiteList>]
    [<blackList>
        <addr [op="{op}"]>...</addr>+
    </blackList>]
</ModifyWhiteBlackListRequest>

Note:
    If no <addr> is present in a list, it means to remove all addresses
    in the list.

    e.g. remove all addresses in the white list
         <ModifyWhiteBlackListRequest>
             <whiteList/>
         </ModifyWhiteBlackListRequest>


{op} = + | -
       + : add, ignored if the value already exists
       - : remove, ignored if the value does not exist
       if not present, replace the entire list with provided values.

       Note, can't mix +/- with non-present op)

       e.g.
       1. replace the entire white list with "foo", "bar".
              <whiteList>
                  <addr>foo</addr>
                  <addr>bar</addr>
              </whiteList>

       2. add values "foo" and "bar" to white list
              <whiteList>
                  <addr op="+">foo</addr>
                  <addr op="+">bar</addr>
              </whiteList>

       3. remove values "foo" and "bar" from white list
              <whiteList>
                  <addr op="-">foo</addr>
                  <addr op="-">bar</addr>
              </whiteList>

       4. add "foo" and remove 'bar"
              <whiteList>
                  <addr op="+">foo</addr>
                  <addr op="-">bar</addr>
              </whiteList>

       5. mix +/- and non-present op - now allowed, INVALID_REQUEST will be thrown
              <whiteList>
                  <addr op="+">foo</addr>
                  <addr>bar</addr>
              </whiteList>


<ModifyWhiteBlackListResponse/>


----------------------------
<GetShareInfoRequest [includeSelf="1|0"]>
    [<grantee type="{grantee_type}" [id="{grantee-id}"] [name="{grantee-name}"]/>]
    [<owner by="{owner-by}">...</owner>]
</GetShareInfoRequest>

{includeSelf}  = 0 if shares owned by the requested account should not be included in the response
                 1 (default) include shares owned by the requested account
                 (It might be useful to see the shares I've shared to a DL that I belong to so
                 that I know I'm sharing it correctly.)

{grantee_type} = if specified, filters the result by the specified grantee type.

{grantee-id}   = if specified, filters the result by the specified grantee id.

{grantee-name} = if specified, filters the result by the specified grantee name.

Notes on {grantee_type}, {grantee-id}, {grantee-name}:
  - it's recommended that only one of {grantee_type}, {grantee-id}, {grantee-name} is specified.
  - if multiple are specified and they conflict, e.g. {grantee-type} is grp but
    {grantee-id} contains an account id, obviously no result will be returned because
    no grant will be matching that condition.

{owner-by}     = name | id
                 Note: In order to defend against harvest attacks this SOAP call will
                 return "no shares" instead of error when an invalid user name/id is used.

Notes:
- if <owner> is *not* specified server will search the LDAP for published shares (zimbraSharedItem
  account attribute) accessible to the authed user.

- if <owner> *is* specified, server will iterate through the owner's mailbox to discover all
  shares applicable to the authed user, instead of looking at any of the published share info.
  All applicable shares will be returned, including any shares that are:
        - shared with the account directly
        - shared with any group(and parent groups) the account belongs. (*is* supported)
        - shared with the cos assigned to the account.                  (*is* supported)
        - shared with the domain this account is in.                    (*is* supported)
        - shared with all authed users (i.e. all Zimbra users)          (*is* supported)
        - shared with the public                                        (*is* supported)


    e.g.
    1. What folders are shared with any of the groups I belong to?

        1a. folders of any user
                <GetShareInfoRequest>
                    <grantee type="grp">
                </GetShareInfoRequest>

        1b. folders of a particular user
                <GetShareInfoRequest>
                    <grantee type="grp">
                    <owner by="name">user1@example.com</owner>
                </GetShareInfoRequest>

    2. What folders does a particular user share with me?
        2a. include all folders directly shared with me and shared
            with an entry I can inherit shares from:
                <GetShareInfoRequest>
                    <owner by="name">user1@example.com</owner>
                </GetShareInfoRequest>

        2b. include only folders directly shared with me.
                <GetShareInfoRequest>
                    <grantee type="usr">
                    <owner by="name">user1@example.com</owner>
                </GetShareInfoRequest>

    3. Show me all folders shared directly with me and with any entry I can inherit shares from:
                <GetShareInfoRequest>
                </GetShareInfoRequest>


<GetShareInfoResponse>
    [<share ownerId="{owner-id}" ownerEmail={owner-email} [ownerName="{owner-display-name}"]
            folderId="{folder-id}" folderPath="{fully-qualified-path}"
            view="{default-type}" [mid="{mountpoint-id}"] rights="{rights}"
            granteeType="{grantee-type}" granteeId="{grantee-id}" granteeName="{grantee-name}" [granteeDisplayName="{grantee-display-name}">]]+
</GetShareInfoResponse>

mid="{mountpoint-id}" : returned if the share is already mounted.
                        contains the folder id of the mountpoint in the local mailbox.


----------------------------

<SendShareNotificationRequest [action="edit|revoke|expire"]>
    <item id="{item-id}"/>
    [<e a="{email-addr}"/>]+
    [<notes>{notes}</notes>]
</SendShareNotificationRequest>

The client can list the recipient email addresses for the share, along
with the itemId of the item being shared.

Request with "action=edit" indicates that permissions were modified for an
existing share.

A request with "action=expire" is sent by the system itself, when a share
expires and is automatically revoked.

<SendShareNotificationResponse/>

----------------------------

<GetEffectiveFolderPermsRequest>
  <folder l="{folder-id}"/>]
</GetEffectiveFolderPermsRequest>

returns the effective permissions of the specified folder

<GetEffectiveFolderPermsResponse>
  <folder perm="{permissions}"/>
</GetEffectiveFolderPermsResponse>


----------------------------

<RankingActionRequest>
  <action op="reset|delete" [email="{email-address}"] />
</RankingActionRequest>

<RankingActionResponse/>

reset - resets the contact ranking table for the account
delete - delete the ranking information for the email address

----------------------------

<ModifyZimletPrefsRequest>
    <zimlet name="{name}" presence="{enabled|disabled}"/>+
</ModifyZimletPrefsRequest>

<ModifyZimletPrefsResponse>
    <zimlet name="{name}" presence="{enabled|disabled}"/>+
</ModifyZimletPrefsResponse>

----------------------------

<GenerateUUIDRequest/>

<GenerateUUIDResponse>{generated UUID}</GenerateUUIDResponse>

Ajax client can use this request to ask the server for help in generating a proper, globally unique UUID.


-----------------------------

<GetDistributionListMembersRequest [limit="{limit}"] [offset="{offset}"]>
  <dl>{dl-name}</dl>
</GetDistributionListMembersRequest>

<GetDistributionListMembersResponse more="{more-flag}" [total="{total}"]>
    <dlm>{member email}</dlm>+
    <groupMember name={member email}>
      <attr name={attribute-name}>{attribute-value}</attr>+
    </groupMember>+
</GetDistributionListMembersResponse>

Notes:
    limit - the number of members to return (0 is default and means all)
    offset - the starting offset (0, 25, etc)

    more-flag = true if more members left to return
    total = total number of distribution lists (not affected by limit/offset)
    
    returns group members in <dlm> element, sorted ascendingly by email address for non-hab distribution lists
    For HAB Groups, it returns group members with their details in groupMember element, sorted by seniorityIndex and then by name.

-----------------------------

<PurgeRevisionRequest>
  <revision id="{item-id}" ver="{revision}" [includeOlderRevisions="true|false"]/>
</PurgeRevisionRequest>

<PurgeRevisionResponse/>

When includeOlderRevisions is set to true, the server will purge all the
old revisions inclusive of the revision specified in the request.

-----------------------------

<SendVerificationCodeRequest a="{device-email-address}"/>

<SendVerificationCodeResponse/>

Notes: SendVerificationCodeRequest results in a random verification code being generated and sent to a device.


<VerifyCodeRequest a="{device-email-address}" code="{verification-code}"/>

<VerifyCodeResponse success="0|1">

Notes: Request for validating the verification code sent to a device. After successful validation the server
sets device email address as the value of zimbraCalendarReminderDeviceEmail account attribute.


<InvalidateReminderDeviceRequest a="{device-email-address}"/>

<InvalidateReminderDeviceResponse/>

-----------------------------

<AddCommentRequest>
  <comment parentId="{item-id-of-parent}" text="{comment-text}"/>
</AddCommentRequest>

<AddCommentResponse>
  <comment id="{item-id}"/>
</AddCommentResponse>

Add the comment to specified item.  Currently the comments can be
added to Documents only.

-----------------------------

<GetCommentsRequest>
  <comment parentId="{item-id-of-parent}"/>
</GetCommentsRequest>

<GetCommentsResponse>
  [<user id="{account-id}" name="{display-name}" email="{email-address}"/>]*
  [<comment id="{item-id}" parentId="{item-id-of-parent}" email="{creator-email-address}" d="{timestamp}" text="{comment-text}"/>]+
<GetCommentsResponse>

----------------------------

<GetShareNotificationsRequest/>

<GetShareNotificationsResponse>
   [<share id="{notification-item-id}" d="{date}" status="new|seen">
      <grantor id="{zimbra-id}" email="{email-address}" name="{display-name}"/>
      <link id="{shared-item-id}" name="{item-name}" view="{item-type}" perm="{permissions-granted}"/>
    </share>]*
   [<revoke id="{notification-item-id}" d="{date}" [expire="1"]>
      <grantor id="{zimbra-id}" email="{email-address}" name="{display-name}"/>
      <link id="{revoked-item-id}" name="{item-name}" view="{item-type}"/>
    </revoke>]*
</GetShareNotificationsResponse>

    There will be at most one <share/> or <revoke/> block for each shared item
    regardless of how many times the share notification was re-sent by the
    owner.  <revoke/> indicates the previous share is no longer available
    to the user and should be hidden or removed from the UI. If "expire=1" is set
    on <revoke/> it indicates that the share expired and was automatically revoked
    by the system.
    
    notification-item-id = the id of the share notification message.  The message must be in the Inbox folder.
    status is "new" if the message is unread or "seen" if the message is read.
    perm = combination of r (read) w (write) i (insert) d (delete) x (action) a (admin)

-----------------------------

<GetSystemRetentionPolicyRequest/>

<GetSystemRetentionPolicyResponse>
  <retentionPolicy>
    <keep>
      <policy id="{id}" name="{name}" type="system" lifetime="{duration}"/>*
    </keep>
    <purge>
      <policy id="{id}" name="{name}" type="system" lifetime="{duration}"/>*
    </purge>
  </retentionPolicy>
</GetSystemRetentionPolicyResponse>

-----------------------------

<CreateDistributionListRequest [dynamic="1|0"]>
  <name>...</name>
  <a n="...">...</a>+
</CreateDistributionListRequest>

<CreateDistributionListResponse>
  <dl name="{name}" id="{id}" ref="{dl-ldap-dn}">
    <a n="...">...</a>+
  </dl>
</CreateDistributionListResponse>

Notes:
  authed account must have the privilege to create dist lists in the domain

  dynamic: 1(default): create a dynamic distribution list
           0:  create a static distribution list
           

-----------------------------

<GetDistributionListRequest needOwners="1|0" needRights="{comma-separated-rights}">
  <dl by="id|name">...</dl>
</GetDistributionListRequest>

  needOwners = whether to return owners, default is 0 
               1: return owners
               0: don't return owners
               
  needRights = return grants for the specified (comma-separated) rights.
               e.g. needRights="sendToDistList,viewDistList"
               

<GetDistributionListResponse >
  <dl name="{name}" id="{id}" dynamic="1|0" [isOwner="1"] [isMember="1"]>
    <a n="...">...</a>+
    [<owners>
      <owner type="{grantee-type}" id="{owner-id}" name="{owner-name}"/>+
    </owners>]
    [<rights>
      [<right right="{right}"> 
           <grantee type={grantee-type} [id="{grantee-id}"] [name="grantee-name"]/>
       </right>+]  
    </rights>]
  </dl>
</GetDistributionListResponse>

Notes:
   If the authed account is one of the list owners, all (requested) attributes of the DL
   are returned in the response.  Otherwise only attributes visible and useful to
   non-owners are returned.
   
   Specified <rights> are returned only if the authed account is one of the list owners.
   Only grants on this group entry is returned, inherited grants on domain or globalgrant 
   are not returned.

   dynamic = whether this is a dynamic distribution list
   grantee-type = 
                usr - a Zimbra internal user
                grp - a Zimbra internal group
                egp - an external AD group
                all - all Zimbra users (id and name will not be present)
                pub - public (id and name will not be present)
     
-----------------------------

<DistributionListActionRequest>
  <dl by="id|name">...</dl>
  <action op="{op}">
      [<a n="...">...</a>+]
      [<newName>{new-DL-name}</newName>]
      [<owner type={grantee-type} by="name|id}">{name-or-id}</owner>+]
      [<right right="{right}"> 
           <grantee type={grantee-type} by="name|id}">{name-or-id}</grantee>+
       </right>+]  
      [<dlm>{member}</dlm>+]
      [<subsReq op="subscribe/unsubscribe" [bccOwners="1|0"]>{member-email}</subsReq>]
  </action>
<DistributionListActionRequest>

Notes:
  authed account must be one of the list owners

  op = delete         delete the list
       rename         rename the list
       modify         modify the list
       addOwners      add list owner
       removeOwners   remove list owners
       setOwners      set list owners
       grantRights    grant rights
       revokeRights   revoke rights
       setRights      set rights
       addMembers     add list members
       removeMembers  remove list members
       acceptSubsReq  accept subscription/un-subscription request
       rejectSubsReq  reject subscription/un-subscription request

  grantee-type:      
     usr - a Zimbra internal user
     grp - a Zimbra internal group
     egr - an external AD group
     all - all Zimbra users (by and {name-or-id} are ignored)
     pub - public (by and {name-or-id} are ignored)
     email - an email address.  Server will lookup in directory and determine the actual grantee
     

  <a>       required if op=modify
  <newName> required if op=rename
  <owner>   required if op=addOwners or op=removeOwners, 
            optional if op=setOwners.  If not present when op=setOwners all current 
            owners will be removed.
  <right>   required if op=grantRight, op=revokeRight, op=setRight.
  <grantee> (sub-element of <right>)
            required if op=grantRight, op=revokeRight
            optional if op=setRight.  If not present when op=setSenders all current 
            grants for the right will be removed.            
  <dlm>     required if op=addMembers or op=removeMembers
  <subsReq> required if op=acceptSubsReq or op=rejectSubsReq    
  
  Note: 
        For owners/rights, only grants on the group itself will be 
        modified, grants on domain and globalgrant (from which the right can be inherited) 
        will not be touched.  Only admins can modify grants on domains and globalgrant, 
        owners of groups can only modify grants on the group entry.
        
        
        
  bccOwners = whether to bcc all other owners on the accept/reject notification emails.
              1(default): bcc all other owners
              0: do not bcc any other owners

<DistributionListActionResponse/>

-----------------------------

<SubscribeDistributionListRequest op="subscribe/unsubscribe">
  <dl by="id|name">...</dl>
</SubscribeDistributionListRequest>

{op} = subscribe: subscribe the requested account to the list
       unsubscribe: unsubscribe the requested account from the list

<SubscribeDistributionListResponse status={status}/>

{status} = subscribed | unsubscribed | awaiting_approval;



-----------------------------

<GetAccountDistributionListsRequest [ownerOf="{owner-of}"] [memberOf="{member-of}] [attrs="{attrs}"]">
</GetAccountDistributionListsRequest>

<GetAccountDistributionListsResponse>
  <dl name="{name}" id="{id}" ref="{dl-ldap-dn}" [d="{display-name}"] [via="{via-dl-name}] [isOwner="1|0"] [isMember="1|0"]>
    [<a n="...">...</a>+]
  </dl>+
</GetAccountDistributionListsResponse>


Returns groups the user is either a member or an owner of.

Note: isOwner is returned only if ownerOf on the request is 1.
      isMember is returned only if memberOf on the request is not "none".
      For example, if ownerOf="1" and memberOf="none" on the request, and 
      user is an owner and a member of a group, the returned entry for the group 
      will have isOwner="1", but isMember will not be present.

{owner-of} = 1: needs groups the user is an owner of.
             0 (default): do not need groups the user is an owner of.
             
{member-of} = all: needs all groups the user is a direct or indirect member of.
              none: do not need groups the user is a member of.
              directOnly (default): needs groups the account is a direct member of.    
              
{attrs} = comma-separated attributes to return.  Note: non-owner user can see only certain 
          attributes of a group.  If a specified attribute is not visible to the user,
          it will not be returned.

{via-dl-name} = is present if the account is a member of the returned list because 
                they are either a direct or indirect member of another list that is 
                a member of the returned list. 
                For example,
                if a user is a member of engineering@domain.com, and engineering@domain.com 
                is a member of all@domain.com, then 
                <dl name="all@domain.com" ... via="engineering@domain.com"/> 
                would be returned.


-----------------------------
GetOAuthConsumerRequest:
This is OAuth related API used for fetching details of OAuth consumers/apps for an account.
Response for this API include access token(this acts as a key), application name, device information, approved on date.

```
<GetOAuthConsumersRequest xmlns="urn:zimbraAccount"/>

<GetOAuthConsumersResponse xmlns="urn:zimbraAccount">
      <OauthConsumer approvedOn="{approved-on}" appName="{name-of-consumer}" accessToken="{access-token}" device="{device-name}"/>
      <OauthConsumer .../>
        ....
    </GetOAuthConsumersResponse>
```

-----------------------------
RevokeOAuthConsumerRequest:
This is OAuth related API used for revoking access for an OAuth consumer.
<RevokeOAuthConsumerRequest
    accessToken="9230ae1e4828b108e7696f66e2dc3c80"
    xmlns="urn:zimbraAccount"/>
```
<RevokeOAuthConsumerResponse xmlns="urn:zimbraAccount"/>```

-----------------------------
ListIMAPSubscriptionsRequest:
Returns the list of folders that this account has subscribed to via IMAP

<ListIMAPSubscriptionsRequest/>

<ListIMAPSubscriptionsResponse xmlns="urn:zimbraAccount">
    [<sub>{folder path}</sub>]+
</ListIMAPSubscriptionsResponse>

-----------------------------
SaveIMAPSubscriptionsRequest:
Saves the list of folders that this account has subscribed to via IMAP

<SaveIMAPSubscriptionsRequest>
    [<sub>{folder path}</sub>]+
</SaveIMAPSubscriptionsRequest>

<SaveIMAPSubscriptionsResponse xmlns="urn:zimbraAccount"/>

-----------------------------
OpenIMAPFolderRequest:
Returns a paginated list of IMAP messages in a folder. If the specified limit
is reached while more items remain, the response will contain the more="1" attribute,
and the next request should contain the "cursor" element with the "id" attribute
set to the item ID of the last message in the previous result set.

<OpenIMAPFolderRequest l="{folder-id}" limit="{...}">
    [<cursor id="{prev-id}"]
</OpenIMAPFolderRequest>

<OpenIMAPFolderResponse more="0|1">
    <folder>
        [<m i4uid="{imap-uid}" t="{type}" f="{flags}" id="{item-id}"/>]
        ...
    </folder>
    [<cursor id="{prev-id}"]
</OpenIMAPFolderResponse>

-----------------------------
BeginTrackingIMAPRequest:
Signals to the server to being tracking IMAP for the mailbox associated with the account.
If IMAP tracking is already enabled, does nothing.

<BeginTrackingIMAPRequest/>

<BeginTrackingIMAPResponse/>

-----------------------------
API to restore contact backup file from the contact backup list
<RestoreContactsRequest contactsBackupFileName="{backup_file_name}" resolve="{restore_resolve}">
</RestoreContactsRequest>

{restore_resolve} = ignore | modify | reset | replace

Note: First, retrieve the contact backup file name with GetContactBackupList Soap API,
then send that file name in 'contactsBackupFileName' parameter of RestoreContactsRequest.
RestoreContactsRequest will search for file inside 'ContactsBackup' briefcase folder
and if found, will restore it.
The 'resolve' parameter is optional. It supports ignore, modify, reset, replace options in
import Rest API. By default, the resolve action is 'reset'.

<RestoreContactsResponse>
</RestoreContactsResponse>

-----------------------------
Api to get list of available contact backup files
<GetContactBackupListRequest xmlns="urn:zimbraMail" />

<GetContactBackupListResponse xmlns="urn:zimbraMail">
  [<backups>
    <backup>file1_name</backup>
    <backup>file2_name</backup>
    <backup>file3_name</backup>
    ...
  </backups>]
</GetContactBackupListResponse>

-----------------------------
API to search for mail items and take some bulk action on the search result
<SearchActionRequest>
</SearchRequest>
<BulkAction op={action-to-be-taken-on-search-result} [l={folder-path}]/>
</SearchActionRequest>

Note: <SearchRequest> element is nothing but old search request having same attributes and elements.
In BulkAction, l={folder-path} attribute is optional, it will only be used in actions such as 'move'.
Valid 'op' values: move, read, unread

<SearchActionResponse>
</SearchActionResponse>

-----------------------------
API to save account profile image
<ModifyProfileImageRequest uid="{upload_id}">{base64_encoded_image_data}
</ModifyProfileImageRequest>

{upload_id} = Upload Id of profile image uploaded
{base64_encoded_image_data} = Image data encoded in base64 format

Note: If the {base64_encoded_image_data} is present in the value field, the {upload_id} is ignored.
If the {base64_encoded_image_data} is not present in the request, the {upload_id} is used to fetch the image data.
If both {base64_encoded_image_data} and {upload_id} are not present, the profile image is removed if already exist.

<ModifyProfileImageResponse itemId="{item_id}">
</ModifyProfileImageResponse>

{item_id} = Item Id of saved profile image

Note: The item id returned in response can be used to download the profile image using REST URL

Server Debug config parameters:
1. profile_image_max_size = maximum image size allowed for account profile
2. profile_thumbnail_image_dimension = profile ldap thumbnail image dimesion

-----------------------------
API to set recovery email address
<SetRecoveryAccountRequest op="{op}" recoveryAccount="{recoveryAccount}" recoveryAccountVerificationCode="{recoveryAccountVerificationCode}" channel="email">
</SetRecoveryAccountRequest>

{op} = op can be sendCode, validateCode, resendCode or reset.
{recoveryAccount} = Recovery account address to be set
{recoveryAccountVerificationCode} = Recovery account verification code to validate the account
channel = It is a mandatory attribute with value "email" only. As only email is supported currently.

sendCode: reads input parameter {recoveryAccount}. If the code is not already sent to this account, generates new code and sends to the recovery address. Sets the recovery address status to pending.
validateCode: reads input parameter {recoveryAccountVerificationCode}. If the code is not expired and verified successfully, sets the recovery address status to verified.
resendCode: reads no input parameter. If the code is not yet expired, resends the code to recovery account set in sendCode request. If it is expired, generates new code and resends.
reset: reads no input parameter. 'reset' will clear all ldap attributes related to recovery account.

<SetRecoveryAccountResponse>
</SetRecoveryAccountResponse>

-----------------------------
API to get recovery email address and send recovery code to reset forgotten password.
<RecoverAccountRequest op="{getRecoveryAccount|sendRecoveryCode}" email="{user_email}" channel="email" xmlns="urn:zimbraMail" />

channel = It is a mandatory attribute with value "email" only. As only email is supported currently.
getRecoveryAccount = get recovery account for given channel only if it's verified.
sendRecoveryCode = send recovery code to recovery account using given channel only if it's verified.
user_email = email address of the user who forgot the password.

<RecoverAccountResponse recoveryAccount="{recovery_account}" recoveryAttemptsLeft="{recovery_attempts_left}"/>
recovery_account = verified recovery account for getRecoveryAccount operation
recovery_attempts_left = attempts remaining before feature suspension.

-----------------------------
API to reset password of authenticated account under zimbraAccount namespace.
<ResetPasswordRequest>
    <password>...</password>
</ResetPasswordRequest>
 HERE,
 password = new password to set for account

<ResetPasswordResponse />

-----------------------
Get HAB API
-----------------------
<GetHABRequest habRootGroupId="{id of HAB Group}"/>

</GetHABRequest>

<GetHABResponse>
    <habGroup rootHabGroup="{TRUE|FALSE}" seniorityIndex="{0|1}"
       name="{habGroupName}" id="{habGroupId}" parentHabGroupId="{parentHabGroupId}">
       <a n="...">...</a>+
       {Child groups of this parent group}
       <habGroup rootHabGroup="{TRUE|FALSE}" seniorityIndex="{0|1}"
       name="{habGroupName}" id="{habGroupId}" parentHabGroupId="{parentHabGroupId}">
       </habGroup>+
      
    </habGroup>+
 </GetHABResponse>
   

----------------------------
API to get all active address lists in the user's domain
<GetAllAddressListsRequest xmlns="urn:zimbraAccount"/>

Returns list of address lists.
      <GetAllAddressListsResponse xmlns="urn:zimbraAccount">
         <AddressLists>
            <AddressList name={name_of_address_list} [description={description}] id={zimbraId}/>
            ...
         </AddressLists>
      </GetAllAddressListsResponse>

-----------------------------
GetAddressListMembers

API to get the members of an address list

Request:
<GetAddressListMembersRequest limit="{max result items}" offset="{offset from which result should be returned}"   id="{address list id}" countOnly="0|1{if only total account is returned}"/>

Response
<GetAddressListMembersResponse xmlns="urn:zimbraAccount">
 <alm total="{total members in query result}">
 <member>{email}</member>+
</alm>
</GetAddressListMembersResponse>

-----------------------------
GetAddressListInfo

API to get the meta info of an address list.
Address list may be requested by id, or name and domain.
If address list is requested by id, name and domain are ignored.

Request:
<GetAddressListInfoRequest name="{address list name}" id="{address list id}">
 <domain by="{by}">{address list domain}</domain>
</GetAddressListInfoRequest>

Response:
<GetAddressListInfoResponse name="{address list name}" id="{address list id}" type="{address list type}" xmlns="urn:zimbraAccount">
 <domain by="name">{address list domain}</domain>
 <desc>{address list description}</desc>
 <searchFilter>
    <conds>
        <cond/>+
    </conds>
 </searchFilter>
</GetAddressListInfoResponse>
