-
-
Notifications
You must be signed in to change notification settings - Fork 0
Plugin Development
Damir Mukimov edited this page Dec 15, 2025
·
4 revisions
Create custom plugins to extend ZoneKit functionality
The plugin system allows you to extend the functionality of ZoneKit with custom integrations for email providers, DNS services, or any other use case.
All plugins must implement the plugin.Plugin interface:
type Plugin interface {
Name() string
Description() string
Version() string
Commands() []Command
}Each plugin can provide multiple commands. Commands receive a Context that provides:
| Component | Description |
|---|---|
Domain |
Domain name being operated on |
DNS |
DNS service for managing records |
Args |
Additional command arguments |
Flags |
Command flags (dry-run, replace, confirm, etc.) |
Output |
Output writer for displaying results |
Create a new directory for your plugin:
mkdir -p pkg/plugin/myemailCreate pkg/plugin/myemail/myemail.go:
package myemail
import (
"fmt"
"zonekit-manager/pkg/dns"
"zonekit-manager/pkg/plugin"
)
const (
pluginName = "myemail"
pluginVersion = "1.0.0"
pluginDescription = "My Email Provider integration"
)
type MyEmailPlugin struct{}
func New() *MyEmailPlugin {
return &MyEmailPlugin{}
}
func (p *MyEmailPlugin) Name() string {
return pluginName
}
func (p *MyEmailPlugin) Description() string {
return pluginDescription
}
func (p *MyEmailPlugin) Version() string {
return pluginVersion
}
func (p *MyEmailPlugin) Commands() []plugin.Command {
return []plugin.Command{
{
Name: "setup",
Description: "Set up email DNS records",
LongDescription: `Set up all necessary DNS records for My Email Provider.
This will add:
- MX records for mail routing
- SPF record for sender authentication
- DKIM records for email signing
- DMARC record for email policy`,
Execute: func(ctx *plugin.Context) error {
return p.setup(ctx)
},
},
{
Name: "verify",
Description: "Verify email DNS records",
Execute: func(ctx *plugin.Context) error {
return p.verify(ctx)
},
},
}
}
func (p *MyEmailPlugin) setup(ctx *plugin.Context) error {
dryRun, _ := ctx.Flags["dry-run"].(bool)
replace, _ := ctx.Flags["replace"].(bool)
// Get existing records if not replacing
var existingRecords []dns.Record
var err error
if !replace {
existingRecords, err = ctx.DNS.GetRecords(ctx.Domain)
if err != nil {
return fmt.Errorf("failed to get existing records: %w", err)
}
}
// Generate DNS records for your email provider
records := []dns.Record{
{
HostName: "@",
RecordType: dns.RecordTypeMX,
Address: "mail.example.com.",
TTL: dns.DefaultTTL,
MXPref: 10,
},
{
HostName: "@",
RecordType: dns.RecordTypeTXT,
Address: "v=spf1 include:_spf.example.com -all",
TTL: dns.DefaultTTL,
},
}
ctx.Output.Printf("Setting up email DNS records for %s\n", ctx.Domain)
if dryRun {
ctx.Output.Println("DRY RUN MODE - No changes will be made")
ctx.Output.Println("Records to be added:")
for _, record := range records {
ctx.Output.Printf(" %s %s → %s\n", record.HostName, record.RecordType, record.Address)
}
return nil
}
// Apply changes
var allRecords []dns.Record
if replace {
allRecords = records
} else {
allRecords = existingRecords
allRecords = append(allRecords, records...)
}
err = ctx.DNS.SetRecords(ctx.Domain, allRecords)
if err != nil {
return fmt.Errorf("failed to set DNS records: %w", err)
}
ctx.Output.Printf("Successfully set up email DNS records for %s\n", ctx.Domain)
return nil
}
func (p *MyEmailPlugin) verify(ctx *plugin.Context) error {
records, err := ctx.DNS.GetRecords(ctx.Domain)
if err != nil {
return fmt.Errorf("failed to get DNS records: %w", err)
}
ctx.Output.Printf("Verifying email setup for %s\n", ctx.Domain)
// Check for required records
hasMX := false
hasSPF := false
for _, record := range records {
if record.RecordType == dns.RecordTypeMX && record.HostName == "@" {
hasMX = true
}
if record.RecordType == dns.RecordTypeTXT &&
record.HostName == "@" &&
strings.Contains(record.Address, "v=spf1") {
hasSPF = true
}
}
if hasMX {
ctx.Output.Println("MX record found")
} else {
ctx.Output.Println("MX record missing")
}
if hasSPF {
ctx.Output.Println("SPF record found")
} else {
ctx.Output.Println("SPF record missing")
}
return nil
}In cmd/root.go, add your plugin registration:
import (
"zonekit-manager/pkg/plugin/myemail"
)
func initPlugins() {
// Existing plugins
plugin.Register(migadu.New())
// Your plugin
plugin.Register(myemail.New())
}# List plugins
zonekit plugin list
# Get plugin info
zonekit plugin info myemail
# Setup email
zonekit plugin myemail setup example.com
# Verify setup
zonekit plugin myemail verify example.com
# Dry run
zonekit plugin myemail setup example.com --dry-runThe Context provided to plugin commands includes:
| Field | Type | Description |
|---|---|---|
Domain |
string |
The domain name being operated on |
DNS |
Service |
DNS service instance for managing records |
Args |
[]string |
Additional command arguments |
Flags |
map[string]interface{} |
Command flags (dry-run, replace, confirm, etc.) |
Output |
OutputWriter |
Output writer for displaying messages |
- Validate Input: Always validate domain names and other inputs
-
Support Dry Run: Implement
--dry-runflag support - Conflict Detection: Check for existing records before modifying
-
Clear Output: Use
ctx.Outputfor all user-facing messages - Error Handling: Return descriptive errors with context
- Documentation: Provide clear descriptions for all commands
-
Use Constants: Use DNS constants from
dnspackage (e.g.,dns.RecordTypeMX,dns.DefaultTTL)
To add new plugin types or capabilities:
- Extend the
Plugininterface if needed - Add new fields to
Contextfor additional capabilities - Update the plugin registry to support new features
- Document the changes in the wiki
If you create a useful plugin, consider contributing it back to the project:
- Fork the repository
- Create your plugin in
pkg/plugin/<plugin-name>/ - Register it in
cmd/root.go - Add tests
- Submit a pull request
See Contributing Guide for more details.