https://github.com/nathanborror/swift-mime-generated
A generated library, commit messages are the prompts used unless otherwise indicated. Currently using Zed Agent with Sonnet 4.5.
https://github.com/nathanborror/swift-mime-generated
Last synced: 3 months ago
JSON representation
A generated library, commit messages are the prompts used unless otherwise indicated. Currently using Zed Agent with Sonnet 4.5.
- Host: GitHub
- URL: https://github.com/nathanborror/swift-mime-generated
- Owner: nathanborror
- Created: 2025-10-16T15:53:53.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-10-17T16:37:29.000Z (3 months ago)
- Last Synced: 2025-10-17T18:29:43.758Z (3 months ago)
- Language: Swift
- Size: 20.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# MIME
A Swift package for parsing MIME formatted multipart data. This library provides a clean, type-safe API for working with MIME messages, making it easy to extract headers, parts, and content from multipart messages.
## Features
- ✅ Parse MIME messages (both multipart and non-multipart) according to RFC 2045 and RFC 2046
- ✅ Optional MIME-Version header (not required for parsing)
- ✅ Case-insensitive header access
- ✅ Support for quoted and unquoted boundaries
- ✅ Automatic charset detection
- ✅ Type-safe API with `Sendable` support for Swift 6
- ✅ Convenient helper methods for common operations
- ✅ No external dependencies
## Requirements
- iOS 18.0+ / macOS 15.0+
- Swift 6.2+
## Installation
Add this package to your project using Swift Package Manager:
```swift
dependencies: [
.package(url: "https://github.com/yourusername/swift-mime-generated.git", from: "1.0.0")
]
```
## Usage
### Multipart Message Example
```swift
import MIME
let mimeString = """
From: sender@example.com
Date: Mon, 01 Jan 2024 12:00:00 -0800
Content-Type: multipart/mixed; boundary="simple"
--simple
Content-Type: text/plain
Hello, World!
--simple
Content-Type: text/html
Hello, World!
--simple--
"""
let message = try MIMEParser.parse(mimeString)
// Access top-level headers
print(message.from) // "sender@example.com"
print(message.date) // "Mon, 01 Jan 2024 12:00:00 -0800"
// Access parts
print(message.parts.count) // 2
for part in message.parts {
print(part.contentType) // "text/plain", "text/html"
print(part.body)
}
```
### Non-Multipart Message Example
Non-multipart messages (like `text/plain`, `text/html`, `application/json`, etc.) are automatically treated as a single part:
```swift
let simpleMessage = """
From: sender@example.com
To: recipient@example.com
Subject: Simple Text Message
Content-Type: text/plain; charset="utf-8"
This is a simple text message without multipart formatting.
It will be parsed as a single part.
"""
let message = try MIMEParser.parse(simpleMessage)
// Convenient access to body for non-multipart messages
if let body = message.body {
print(body) // "This is a simple text message..."
}
// Or access via parts array
print(message.parts.count) // 1
print(message.parts[0].contentType) // "text/plain"
print(message.parts[0].body) // "This is a simple text message..."
```
### Finding Specific Parts
```swift
// Find all parts with a specific content type
let plainParts = message.parts(withContentType: "text/plain")
// Find the first part with a specific content type
if let htmlPart = message.firstPart(withContentType: "text/html") {
print(htmlPart.body)
}
// Check if a message contains a specific content type
if message.hasPart(withContentType: "application/json") {
print("Message contains JSON data")
}
```
### Accessing Headers
Headers are case-insensitive:
```swift
// All of these work (case-insensitive)
let contentType1 = message.headers["Content-Type"]
let contentType2 = message.headers["content-type"]
let contentType3 = message.headers["CONTENT-TYPE"]
// MIME-Version header is optional
let mimeVersion = message.mimeVersion // May be nil
```
Part-specific headers:
```swift
let part = message.parts[0]
print(part.contentType) // "text/plain"
print(part.charset) // "utf-8"
print(part.headers["Custom-Header"])
```
### Complex Example
Here's a more complex example showing a bookmark tracking system:
```swift
let bookmarkData = """
From: Nathan Borror
Date: Wed, 15 Oct 2025 18:42:00 -0700
MIME-Version: 1.0
Content-Type: multipart/bookmark; boundary="bookmark"
--bookmark
Content-Type: text/book-info
Title: Why Greatness Cannot Be Planned
Subtitle: The Myth of the Objective
Authors: Kenneth O. Stanley, Joel Lehman
ISBN-13: 978-3319155234
Published: 18 May 2015
Language: en
Pages: 135
--bookmark
Content-Type: text/quote; charset="utf-8"
Page: 10
Date: Thu, 29 May 2025 16:20:00 -0700
"Sometimes the best way to achieve something great is to stop trying to achieve a particular great thing."
--bookmark
Content-Type: text/note; charset="utf-8"
Page: 10
Date: Thu, 29 May 2025 16:20:00 -0700
This book is turning out to be very cathartic!
--bookmark
Content-Type: text/progress
Page: 65
Date: Wed, 13 Oct 2025 18:42:00 -0700
--bookmark
Content-Type: text/review; charset="utf-8"
Date: Wed, 15 Oct 2025 18:42:00 -0700
Rating: 4.5
Spoilers: false
I enjoyed this book!
--bookmark--
"""
let message = try MIMEParser.parse(bookmarkData)
// Get book info
if let bookInfo = message.firstPart(withContentType: "text/book-info") {
print(bookInfo.headers["Title"]) // "Why Greatness Cannot Be Planned"
print(bookInfo.headers["Authors"]) // "Kenneth O. Stanley, Joel Lehman"
print(bookInfo.headers["ISBN-13"]) // "978-3319155234"
}
// Get all quotes
let quotes = message.parts(withContentType: "text/quote")
for quote in quotes {
print("Page \(quote.headers["Page"] ?? "?"): \(quote.body)")
}
// Get all notes
let notes = message.parts(withContentType: "text/note")
for note in notes {
print(note.body)
}
// Get progress
if let progress = message.firstPart(withContentType: "text/progress") {
print("Currently on page \(progress.headers["Page"] ?? "?")")
}
// Get review
if let review = message.firstPart(withContentType: "text/review") {
print("Rating: \(review.headers["Rating"] ?? "N/A")")
print("Review: \(review.body)")
}
```
## API Reference
### `MIMEParser`
The main entry point for parsing MIME messages. Supports both multipart messages (with boundaries) and non-multipart messages.
#### Methods
- `static func parse(_ content: String) throws -> MIMEMessage`
- Parses a MIME message from a string
- Multipart messages are parsed using the boundary specified in the Content-Type header
- Non-multipart messages are treated as a single part containing the entire body
### `MIMEMessage`
Represents a complete MIME message with headers and parts.
#### Properties
- `headers: MIMEHeaders` - The top-level headers
- `parts: [MIMEPart]` - The individual parts of the message
- `body: String?` - The body content for non-multipart messages (returns nil for multipart messages)
- `from: String?` - The "From" header value
- `to: String?` - The "To" header value
- `subject: String?` - The "Subject" header value
- `date: String?` - The "Date" header value
- `mimeVersion: String?` - The "MIME-Version" header value (optional, may be nil)
- `contentType: String?` - The "Content-Type" header value
#### Methods
- `func parts(withContentType contentType: String) -> [MIMEPart]`
- Returns all parts with a specific content type
- `func firstPart(withContentType contentType: String) -> MIMEPart?`
- Returns the first part with a specific content type
- `func hasPart(withContentType contentType: String) -> Bool`
- Returns true if any part has the specified content type
### `MIMEPart`
Represents a single part of a multipart MIME message.
#### Properties
- `headers: MIMEHeaders` - The headers for this part
- `body: String` - The body content
- `contentType: String?` - The content type (e.g., "text/plain")
- `charset: String?` - The charset (e.g., "utf-8")
- `decodedBody: String` - The decoded body content
### `MIMEHeaders`
A case-insensitive dictionary for MIME headers.
#### Methods
- `subscript(key: String) -> String?` - Access headers by name (case-insensitive)
- `func contains(_ key: String) -> Bool` - Check if a header exists
- Conforms to `Collection`, so you can iterate over headers
### `MIMEError`
Errors that can occur during parsing.
#### Cases
- `invalidFormat` - The MIME message format is invalid
- `invalidEncoding` - The character encoding is invalid or unsupported
## Testing
Run the test suite:
```bash
swift test
```
## License
[Your License Here]
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.