Automate Excel on macOS with Python
Most Excel automation advice assumes Windows: win32com.client.Dispatch("Excel.Application"), VBA-style COM calls, Task Scheduler. On a Mac none of that exists — there is no COM, and pywin32 will not install. Excel for Mac can still be automated from Python, but the route depends on what the job really needs. Often it needs no Excel at all: reading, writing and formatting .xlsx files works identically on every platform with pandas and openpyxl. When Excel itself must do something — recalculate a model, refresh a query, export with its own renderer — xlwings drives Excel for Mac through Apple's scripting bridge, and plain AppleScript fills the gaps. This page sorts out which to use and covers the macOS-specific hurdles: privacy permissions, the sandbox, and scheduling. It belongs to Automating Excel with COM and pywin32, whose Windows techniques this page translates.
Prerequisites
pip install xlwings openpyxl pandas
Steps that control Excel need Excel for Mac (Microsoft 365) and are marked as not run, because our build runs on Linux; the file-based step runs anywhere. Examples use a workbook forecast_model.xlsx in your home folder, with an Inputs sheet and formulas on a Model sheet.
Step 1 — Decide whether you need Excel at all
The single biggest simplification on a Mac is noticing that the job is file work:
import pandas as pd
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.title = "Inputs"
ws.append(["Assumption", "Value"])
ws.append(["Growth", 0.04])
ws.append(["Price", 89.0])
wb.save("forecast_model.xlsx")
print(pd.read_excel("forecast_model.xlsx", sheet_name="Inputs"))
pandas and openpyxl read and write .xlsx files without Excel, on macOS exactly as on Windows or a Linux server — formatting, formulas, charts, tables and protection included. If a task is "produce a formatted report" or "read last month's numbers", this is the whole answer, and it is also the only answer that keeps working when the script moves to a server. Excel becomes necessary only when something must be calculated or rendered by Excel: formulas evaluated with Excel's engine, data connections refreshed, Excel's own PDF output. The library choice is covered in Choosing a Python Excel Library.
Step 2 — Drive Excel for Mac with xlwings
xlwings uses the same Python API on macOS and Windows; only its plumbing differs:
import xlwings as xw
from pathlib import Path
path = Path.home() / "forecast_model.xlsx"
app = xw.App(visible=False)
try:
wb = app.books.open(str(path))
wb.sheets["Inputs"]["B2"].value = 0.05 # change an input
app.calculate() # let Excel recalculate
result = wb.sheets["Model"]["B10"].value
print("forecast with 5% growth:", result)
wb.save()
wb.close()
finally:
app.quit()
Opening, writing values, recalculating, reading results and saving look exactly like the Windows examples in Read and Write a Live Excel Workbook with xlwings. That portability is the main reason to prefer xlwings over raw AppleScript. The try/finally matters as much on a Mac as on Windows: a script that crashes halfway otherwise leaves an invisible Excel running.
Step 3 — The first-run permission prompts
The first time a Python process controls Excel, macOS asks the user whether Terminal (or your editor, or whichever app launched Python) may control Microsoft Excel. This is macOS's Automation privacy protection:
- Click OK to allow it; the choice is stored under System Settings › Privacy & Security › Automation, where it can be changed later.
- If you clicked Don't Allow, scripts fail with an error mentioning that the application is not allowed to send Apple events; enable the checkbox for Excel under the launching app in that settings page.
- A scheduled job runs under a different parent process than your Terminal, so it may need its own approval — run it once interactively to trigger the prompt.
Excel for Mac is also sandboxed: it can only open files in places it has been granted access to. When a script opens a file in a new folder, Excel may show a Grant File Access dialog and wait. For unattended jobs, keep workbooks in a folder Excel already has access to (opening one file there by hand and granting access usually suffices), so no dialog can block the run.
Step 4 — The .api escape hatch is different on a Mac
On Windows, .api returns a COM object and VBA-style code works: rng.api.Font.Bold = True. On macOS, .api returns an appscript reference to Excel's AppleScript object model, which uses different names and call style. The xlwings properties hide that difference, so use them wherever they exist:
rng = wb.sheets["Model"]["A1:D1"]
rng.font.bold = True # works on both platforms
rng.color = "#E0E7FF" # works on both platforms
rng.number_format = "#,##0.00" # works on both platforms
import sys
if sys.platform == "darwin":
rng.api.font_object.bold.set(True) # appscript style (macOS)
else:
rng.api.Font.Bold = True # COM style (Windows)
The macOS line is the same call xlwings itself makes internally for font.bold — a property read with .get() and written with .set() on the range's font_object. The rule of thumb: write against xlwings' own API, and keep any .api calls in a small, clearly marked platform branch. Code translated from a recorded VBA macro will almost always be the Windows form. The general formatting properties are listed in Format Cells in a Live Workbook with xlwings.
Step 5 — AppleScript from Python for the gaps
For a one-off command that neither xlwings nor openpyxl covers, Excel's AppleScript dictionary is available through the osascript command-line tool:
import subprocess
script = f'''
tell application "Microsoft Excel"
open POSIX file "{path}"
calculate full
save active workbook
close active workbook saving no
end tell
'''
result = subprocess.run(["osascript", "-e", script], capture_output=True, text=True, timeout=120)
print(result.returncode, result.stdout.strip(), result.stderr.strip())
osascript -e runs the script and returns its output; check returncode and stderr, because AppleScript errors (a missing file, a permission refusal) are reported there rather than as Python exceptions. Excel's dictionary — viewable in Script Editor via File › Open Dictionary — lists every command; build and test scripts there first, then paste them into Python. Keep AppleScript for small gaps: anything substantial is easier to maintain in xlwings, which also runs on Windows.
Step 6 — Schedule it with launchd
The Mac equivalent of Task Scheduler or cron is launchd, configured with a small property-list file in ~/Library/LaunchAgents. Because controlling Excel needs a logged-in user session (Excel is a GUI application), use a LaunchAgent, not a system-wide daemon, and expect the job to run only while that user is logged in. File-only jobs from Step 1 have no such restriction and can run anywhere. The full setup, including the plist and log files, is in Schedule a Python Excel Script on macOS with launchd.
Common pitfalls
- Installing pywin32 on a Mac. It is Windows-only; use xlwings or file-based libraries.
- Using Excel when the file is enough. openpyxl and pandas need no permissions, no Excel and no logged-in user.
- Ignoring the permission prompt. A refused Automation permission makes every script fail until it is re-enabled in System Settings.
- Files outside Excel's granted folders. The Grant File Access dialog blocks unattended runs; keep files in an approved folder.
- Windows
.apicode on a Mac. COM-style calls fail; stick to xlwings' own API or branch by platform. - Hard-coded Windows paths.
C:\Reports\file.xlsxmeans nothing on a Mac; build paths withpathlib.Path, as in the examples, so the same script runs on both.
Conclusion
On a Mac, start by asking whether Excel is needed at all — pandas and openpyxl handle file work on every platform. When Excel's engine is required, drive it with xlwings, whose API is the same as on Windows, approve the Automation permission and Excel's file-access prompt once, and keep any .api code in a platform-specific branch. Use AppleScript through osascript for the rare missing command, and schedule GUI-dependent jobs with a launchd LaunchAgent in a logged-in session.
Frequently asked questions
Can I use pywin32 or win32com on a Mac? No. COM and pywin32 exist only on Windows. On macOS, use xlwings to control Excel, or openpyxl and pandas to work with .xlsx files without Excel.
Does xlwings work on macOS? Yes. xlwings drives Excel for Mac through Apple's scripting bridge, and its own API — opening books, reading and writing ranges, formatting, calculating — is the same as on Windows. Only code that uses .api differs.
Why does my Python script say it is not allowed to send Apple events to Excel? macOS blocked the Automation permission for the app that launched Python. Enable Microsoft Excel for that app under System Settings, Privacy & Security, Automation, then run the script again.
How do I schedule an Excel automation script on a Mac? Use launchd with a LaunchAgent plist in ~/Library/LaunchAgents. Jobs that control Excel need the user to be logged in; jobs that only use openpyxl or pandas do not.
Related
- Up one level: Automating Excel with COM and pywin32 — the Windows side of Excel automation.
- xlwings vs pywin32 for Excel Automation — why xlwings is the portable choice.
- Automate LibreOffice Calc from Python with UNO — a spreadsheet engine without Excel.
- Python vs Office Scripts for Excel Automation — cloud-side automation that is platform-neutral.
More on com & pywin32
- How-toTest win32com and xlwings Code Without Excel
- How-toExport an Excel Chart as an Image with Python
- How-toClose Excel Cleanly and Avoid Orphan COM Processes
- FixHandle COM Errors and Excel Dialog Prompts in Python
- How-toPrint an Excel Workbook from Python with win32com
- How-toRead and Write Cell Ranges with win32com