Convert HTML email templates with embedded images into native Outlook Template Files (.oft)
A Docker-based pipeline that combines Python and .NET to seamlessly transform HTML emails into native Outlook templates, preserving all inline images and formatting.
- Batch Processing: Automatically process multiple email templates from different folders
- Image Embedding: Converts local images to Content-ID (CID) references for proper email embedding
- Docker-Based: No local dependencies required - everything runs in containers
- Simple Workflow: Drop your HTML + images in a folder, get ready-to-use .oft files
- Production Ready: Built to handle real-world email templates with complex layouts
- Docker Desktop installed (Download here)
- Clone this repository:
git clone https://github.com/jaimegvalero/html2oft-converter.git
cd html2oft-converter- Prepare your email templates in the
mail/directory:
mail/
├── welcome_email/
│ ├── index.html
│ └── img/
│ ├── logo.png
│ └── banner.jpg
└── newsletter/
├── index.html
└── img/
└── header.png
- Run the converter:
docker compose up --build- Find your
.oftfiles in theoutput/directory:
output/
├── welcome_email.oft
└── newsletter.oft
The conversion follows a 3-stage pipeline:
HTML + Images → Python (EML) → .NET (OFT) → Outlook Template
-
Python Stage (
generate_eml.py):- Parses HTML file using BeautifulSoup4
- Extracts local images and converts
srcattributes to CID references - Generates RFC-compliant EML file with embedded images
-
.NET Stage (
Program.cs):- Reads EML using MimeKit
- Converts to MSG format using MsgKit 2.3.0
- Exports as native Outlook Template (.oft)
-
Docker Orchestration (
compose.yml):- Manages the multi-stage build process
- Handles dependencies (.NET SDK 8.0, Python 3, libraries)
- Executes batch processing script
Process all templates in the mail/ directory:
docker compose up --buildThis will:
- Build the Docker image with all dependencies
- Process each folder in
mail/ - Generate individual
.oftfiles named after their source folders - Display a summary with success/failure counts
Note: Only use --build when you modify the Dockerfile or dependencies. For subsequent runs with just email changes, use docker compose up.
To process a single email manually:
# Generate EML
python3 generate_eml.py mail/welcome_email temp/output.eml
# Convert to OFT (requires .NET 8.0 SDK)
cd /path/to/dotnet/project
dotnet run /path/to/input.eml /path/to/output.oft.
├── generate_eml.py # Python: HTML → EML converter
├── Program.cs # C#: EML → OFT converter
├── process_all.sh # Bash: Batch processing orchestrator
├── Dockerfile # Multi-stage build configuration
├── compose.yml # Docker Compose orchestration
├── mail/ # Input: Email template folders
│ └── {template_name}/
│ ├── index.html # HTML email template
│ └── img/ # Images referenced in HTML
├── output/ # Output: Generated .oft files
└── temp/ # Temporary .eml files
The converter processes images in two ways:
- Local images (
img/logo.png, etc.) → Embedded as inline attachments with CID references - External URLs (https://example.com/image.png) → Left unchanged as external references
- Python: BeautifulSoup4 for HTML parsing
- .NET: MsgKit 2.3.0 and MimeKit for email/MSG handling
- Docker: .NET SDK 8.0 base image
This project uses MsgKit 2.3.0 (or later) with the following API:
email.Attachments.Add(stream, fileName, renderingPosition, isInline, contentId)- Requires separate MemoryStream instances (cannot reuse closed streams)
- Properly handles
IsInlineproperty for embedded images
- ✅ Verify all image files exist in the
img/directory - ✅ Ensure
index.htmluses relative paths (not absolute) - ✅ Check console output for "Attaching:" messages confirming image embedding
If changes to code don't reflect:
docker compose down
docker compose up --buildThis is handled correctly in the current version. The code:
- Decodes content to byte array first
- Creates a new MemoryStream from the byte array
- Passes the new stream to
email.Attachments.Add()
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with MsgKit for MSG/OFT generation
- Uses MimeKit for MIME parsing
- HTML parsing powered by BeautifulSoup4