Good morning,
I just stumbled upon this topic, I actually made a package for the ZCO very recently, based on the one from the TIS store.
My package is multi-architecture and integrates both versions, 32-bit and 64-bit.
The reason is simple: on a 64-bit machine with a 32-bit version of Outlook installed, the 64-bit package will fail because the ZCO will not install.
My package detects the presence of a 32-bit Outlook and installs the corresponding ZCO (there is certainly a cleaner way to detect Office).
In addition, I define some ZCO parameters via the registry (the same parameters that can be used to customize the MSI, but I didn't want to have to do it every time)

): disabling updates, server address and port, using SSL, disabling aliases in the GAL, and disabling signature synchronization.
To be adapted according to needs (there are other customizable parameters in this registry key).
To address the fact that the uninstall key changes depending on the language, I use an uninstall() function that retrieves the uninstall key of the installed ZCO to uninstall it. Therefore, I don't use the install_msi_if_needed() function.
Finally, the only constraint is that the package version must match the 64-bit ZCO version. If they release different version numbers for the two architectures, then it could cause a problem (but I think that's unlikely).
Edit 03/01/2025:
- Added an audit function to add the Windows Search registry keys from the ZCO that were deleted after an automatic Office update (I personally set the "audit_schedule" parameter to "10m" in the control file), otherwise the non-admin user gets a UAC prompt every time Outlook starts and the search function no longer works (see https://forums.zimbra.org/viewtopic.php?t=67734).
- ZCO configuration correction via the registry on 32-bit Windows
Here is the code for setup.py:
Code: Select all
# -*- coding: utf-8 -*-
from setuphelpers import *
from setupdevhelpers import *
def install():
# Check architecture and if Office is 32bits on 64bits system
regpath = r'SOFTWARE\Zimbra'
if is32() or isdir(makepath(programfiles32, r'Microsoft Office', r'root')):
print(r'INFO: x86 installation detected')
bin_name = 'ZimbraConnectorOLK_x86.msi'
if is64():
regpath = r'SOFTWARE\WOW6432Node\Zimbra'
else:
bin_name = 'ZimbraConnectorOLK_x64.msi'
installed_zco = installed_softwares('Zimbra Connector for Microsoft Outlook')
if not installed_zco or installed_zco[0]['version'] < Version(control.get_software_version(), 4) or WAPT.options.force :
try:
# Installing the software
run(r'msiexec /qn /norestart /i %s' % bin_name, timeout=600)
except Exception as e:
if e.returncode == 1603:
print(f'INFO: Microsoft Outlook needs to be installed.')
error(e)
else:
error(e)
else:
print('%s version %s is already installed, skipping...' % (control.name, installed_zco[0]['version']))
# Customize installation
with reg_openkey_noredir(HKEY_LOCAL_MACHINE, r'SOFTWARE\Zimbra', sam=KEY_WRITE, create_if_missing=True) as key:
reg_setvalue(key, 'SkipVersionUpgrade', '65535', REG_SZ) # disable auto-update
reg_setvalue(key, 'ZimbraServerName', 'smtp.mydomain.tld', REG_SZ) # Zimbra server name
reg_setvalue(key, 'ZimbraServerPort', 443, REG_DWORD) # Zimbra server port
reg_setvalue(key, 'ZimbraConnectionMethod', 1, REG_DWORD) # use SSL
reg_setvalue(key, 'GalSyncDisableAliases', 1, REG_DWORD) # disable alias in GAL
reg_setvalue(key, 'SigSyncEnabled', 0, REG_DWORD) # disable signature sync
def uninstall():
if installed_softwares('Zimbra Connector for Microsoft Outlook'):
key = installed_softwares('Zimbra Connector for Microsoft Outlook')[0]['key']
run('msiexec /qn /norestart /X %s' % key)
def audit():
audit_result = "OK"
# Check architecture and if Office is 32bits on 64bits system
regpath = r'SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Windows\Windows Search\Preferences'
if is64() and isdir(makepath(programfiles32, r'Microsoft Office', r'root')):
regpath = r'SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Wow6432Node\Microsoft\Windows\Windows Search\Preferences'
# Fix Windows Search ZCO registry key if needed
# https://wiki.zimbra.com/wiki/Summary_of_the_registry_keys_that_ZCO_uses
# https://forums.zimbra.org/viewtopic.php?t=67734
for key in [r'{D00FDE68-3E80-4f8c-899D-D9DD16BA7D1D}', r'{FA9628A0-F223-4d5d-B314-E01BC8100572}']:
if registry_readstring(HKEY_LOCAL_MACHINE, regpath, key) != "1":
print(r'Fixing Windows Search ZCO registry key %s...' % key)
registry_set(HKEY_LOCAL_MACHINE, regpath, key, 1, REG_DWORD)
audit_result = "WARNING"
return audit_result
def update_package():
# Declaring local variables
package_updated = False
proxies = get_proxies()
if not proxies:
proxies = get_proxies_from_wapt_console()
url = 'https://www.zimbra.com/product/addons/zimbra-connector-for-outlook-download/'
# Getting latest version from official sources
print('URL used is: %s' % url)
for arch in 'x86', 'x64':
print('Processing %s version...' % arch)
for bs_search in bs_find_all(url, 'a', 'rel', 'noopener', proxies=proxies):
if '_%s.msi' % arch in bs_search.get('href', ''):
download_url = bs_search['href']
latest_bin = download_url.split('/')[-1]
version = latest_bin.split('_')[1]
break
print('Latest %s %s version is: %s' % (control.name, arch, version))
print('Download URL for %s is: %s' % (arch, download_url))
# Downloading latest binaries
print('Downloading: %s' % latest_bin)
latest_bin = '%s_%s' % (latest_bin.split('_')[0], latest_bin.split('_')[2])
wget(download_url, latest_bin, proxies=proxies)
# Checking version from file
version_from_file = get_version_from_binary(latest_bin)
if Version(version_from_file, 4) == Version(version, 4):
print(f'INFO: Binary file version ({version_from_file}) corresponds to online version ({version})')
else:
error(f'ERROR: Binary file version ({version_from_file}) do NOT corresponds to online version ({version})')
# Changing version of the package
if Version(version, 4) > Version(control.get_software_version(), 4):
print('Software version updated (from: %s to: %s)' % (control.get_software_version(), Version(version)))
control.set_software_version(version)
control.save_control_to_wapt()
package_updated = True
else:
print('Software version up-to-date (%s)' % Version(version))
# Validating or not update-package-sources
return package_updated