# Domain Search Bulk

## Overview

[Bulks Domain Search](https://tomba.io/bulks/domain-search) allows you to process thousands of domains simultaneously to discover email addresses, gather domain intelligence, and build comprehensive prospect lists. This powerful feature enables sales and marketing teams to scale their outreach efforts efficiently.

### Key Features

- **Mass Domain Processing**: Search up to 15,000 domains in a single bulk operation
- **Email Discovery**: Find email addresses associated with each domain
- **Email Type Filtering**: Filter results by personal, generic, or department-specific emails
- **Department Targeting**: Focus on specific departments (sales, marketing, engineering, etc.)
- **Result Limits**: Configure maximum emails per domain (1-100)
- **Verification Integration**: Optional email verification for higher deliverability
- **Export Options**: Download results in CSV format with multiple file types
- **Progress Tracking**: Real-time monitoring of bulk processing status

### How Domain Search Bulk Works

1. **Upload Domain List**: Provide domains via text input or CSV file upload
2. **Configure Parameters**: Set email type filters, department preferences, and result limits
3. **Launch Processing**: Initiate the bulk search operation
4. **Monitor Progress**: Track completion status in real-time
5. **Download Results**: Export discovered emails in various formats (full, valid only, not found)

### Limitations

- Each Bulk is limited to 15,000 domains
- Additional rows will be skipped
- Some special or unexpected characters may be deleted in the file
- Invalid websites won't be imported
- Duplicate URLs won't be imported
- For better results, we use the domain name instead of the company name

## Go SDK Integration

### Installation

```bash
go get github.com/tomba-io/go
```

### Basic Domain Search

```go
package main

import (
    "fmt"
    "log"
    "strings"
    "time"

    "github.com/tomba-io/go/tomba"
    "github.com/tomba-io/go/tomba/models"
)

func main() {
    // Initialize Tomba client
    client := tomba.NewClient("YOUR_TOMBA_KEY", "YOUR_TOMBA_SECRET")

    // Basic domain search
    params := &models.BulkSearchCreateParams{
        BulkCreateParams: models.BulkCreateParams{
            Name:    "SaaS Companies Email Search",
            List:    "stripe.com\nshopify.com\nzoom.us\nslack.com\ndropbox.com",
            Sources: true,
            Verify:  true,
        },
        BulkSearchParams: models.BulkSearchParams{
            Maximum: "20", // Find up to 20 emails per domain
        },
    }

    // Create the bulk search
    response, err := client.CreateSearchBulk(params)
    if err != nil {
        log.Fatal("Error creating domain search bulk:", err)
    }

    bulkID := *response.Data.ID
    fmt.Printf("Domain Search Bulk created with ID: %d\n", bulkID)

    // Launch the operation
    launchResp, err := client.LaunchBulk(models.BulkTypeSearch, bulkID)
    if err != nil {
        log.Fatal("Error launching bulk:", err)
    }

    fmt.Printf("Bulk launched: %s\n", launchResp.Data.Message)

    // Monitor progress
    monitorBulkProgress(client, models.BulkTypeSearch, bulkID)

    // Download results
    err = client.SaveBulkResults(models.BulkTypeSearch, bulkID, "./domain_search_results.csv", "full")
    if err != nil {
        log.Printf("Error downloading results: %v", err)
    } else {
        fmt.Println("Results saved to ./domain_search_results.csv")
    }
}
```

### Advanced Domain Search with Filtering

```go
func advancedDomainSearch(client *tomba.Tomba) {
    // Advanced search with department and email type filtering
    searchParams := &models.BulkSearchCreateParams{
        BulkCreateParams: models.BulkCreateParams{
            Name:    "Engineering Contacts - Tech Companies",
            List:    "github.com\natlassian.com\njira.com\nconfluence.com\nbitbucket.com",
            Sources: true,
            Verify:  true,
        },
        BulkSearchParams: models.BulkSearchParams{
            Maximum: "50", // Up to 50 emails per domain
            EmailType: models.BulkSearchParamsType{
                Type:         "personal", // Focus on personal emails
                PriorityType: "priority", // Prioritize personal over generic
            },
            Department: models.BulkSearchParamsDepartment{
                Name:         []string{"engineering", "software", "security"}, // Target departments
                PriorityType: "only", // Only these departments
            },
        },
    }

    response, err := client.CreateSearchBulk(searchParams)
    if err != nil {
        log.Printf("Error creating advanced search: %v", err)
        return
    }

    bulkID := *response.Data.ID
    fmt.Printf("Advanced Domain Search created with ID: %d\n", bulkID)

    // Launch and monitor
    client.LaunchBulk(models.BulkTypeSearch, bulkID)
    monitorBulkProgress(client, models.BulkTypeSearch, bulkID)

    // Download different result types
    downloadTypes := []string{"full", "valid", "not_found"}
    for _, downloadType := range downloadTypes {
        filename := fmt.Sprintf("./advanced_search_%s.csv", downloadType)
        err := client.SaveBulkResults(models.BulkTypeSearch, bulkID, filename, downloadType)
        if err == nil {
            fmt.Printf("Downloaded %s results to %s\n", downloadType, filename)
        }
    }
}
```

### Marketing Team Search

```go
func marketingTeamSearch(client *tomba.Tomba) {
    // Search specifically for marketing contacts
    marketingParams := &models.BulkSearchCreateParams{
        BulkCreateParams: models.BulkCreateParams{
            Name:    "Marketing Contacts - B2B SaaS",
            List:    "hubspot.com\nmailchimp.com\nintercom.com\nzendesk.com\nsalesforce.com",
            Sources: true,
            Verify:  true,
        },
        BulkSearchParams: models.BulkSearchParams{
            Maximum: "30",
            EmailType: models.BulkSearchParamsType{
                Type:         "all", // Include all email types
                PriorityType: "priority",
            },
            Department: models.BulkSearchParamsDepartment{
                Name:         []string{"marketing", "sales", "communication", "pr"},
                PriorityType: "priority", // Prioritize these departments
            },
        },
    }

    response, err := client.CreateSearchBulk(marketingParams)
    if err != nil {
        log.Printf("Error creating marketing search: %v", err)
        return
    }

    bulkID := *response.Data.ID
    fmt.Printf("Marketing Team Search created with ID: %d\n", bulkID)

    // Launch with progress monitoring
    client.LaunchBulk(models.BulkTypeSearch, bulkID)

    // Enhanced monitoring with email count tracking
    monitorWithEmailCounts(client, models.BulkTypeSearch, bulkID)
}
```

### Batch Domain Processing

```go
func batchDomainSearch(client *tomba.Tomba, domains []string, batchSize int) error {
    if len(domains) > 15000 {
        return fmt.Errorf("too many domains: %d (max: 15000)", len(domains))
    }

    // Process in batches for better management
    for i := 0; i < len(domains); i += batchSize {
        end := i + batchSize
        if end > len(domains) {
            end = len(domains)
        }

        batch := domains[i:end]
        batchNum := (i / batchSize) + 1

        fmt.Printf("Processing batch %d (%d domains)...\n", batchNum, len(batch))

        params := &models.BulkSearchCreateParams{
            BulkCreateParams: models.BulkCreateParams{
                Name:    fmt.Sprintf("Domain Batch %d - %s", batchNum, time.Now().Format("Jan 02")),
                List:    strings.Join(batch, "\n"),
                Sources: true,
                Verify:  true,
            },
            BulkSearchParams: models.BulkSearchParams{
                Maximum: "25",
                EmailType: models.BulkSearchParamsType{
                    Type:         "all",
                    PriorityType: "priority",
                },
            },
        }

        response, err := client.CreateSearchBulk(params)
        if err != nil {
            log.Printf("Error creating batch %d: %v", batchNum, err)
            continue
        }

        bulkID := *response.Data.ID

        // Launch batch
        _, err = client.LaunchBulk(models.BulkTypeSearch, bulkID)
        if err != nil {
            log.Printf("Error launching batch %d: %v", batchNum, err)
            continue
        }

        fmt.Printf("Batch %d launched with ID: %d\n", batchNum, bulkID)

        // Small delay between batches
        time.Sleep(3 * time.Second)
    }

    return nil
}
```

### Domain Search Management

```go
func manageDomainSearchBulks(client *tomba.Tomba) {
    // Get all domain search bulks
    allBulks, err := client.GetAllSearchBulks(&models.BulkGetParams{
        Page:      1,
        Limit:     15,
        Direction: "desc",
        Filter:    "all",
    })
    if err != nil {
        log.Printf("Error getting search bulks: %v", err)
        return
    }

    fmt.Printf("Total domain search bulks: %d\n", allBulks.Meta.Total)

    // Analyze and manage bulks
    for _, bulk := range allBulks.Data {
        fmt.Printf("\nBulk: %s (ID: %d)\n", bulk.Name, bulk.BulkID)
        fmt.Printf("  Progress: %d%%, Created: %s\n",
            bulk.Progress, bulk.CreatedAt.Format("2006-01-02 15:04"))

        if bulk.TotalEmails != nil {
            fmt.Printf("  Emails Found: %d\n", *bulk.TotalEmails)
        }

        if bulk.VerifyCost != nil {
            fmt.Printf("  Verification Cost: %d credits\n", *bulk.VerifyCost)
        }

        // Handle completed bulks
        if bulk.Progress >= 100 && !bulk.Used {
            handleCompletedBulk(client, bulk)
        }

        // Handle stuck or failed bulks
        if bulk.Progress < 100 && time.Since(bulk.CreatedAt) > 2*time.Hour {
            fmt.Printf("  ⚠️  Bulk may be stuck (created %v ago)\n", time.Since(bulk.CreatedAt))
        }
    }
}

func handleCompletedBulk(client *tomba.Tomba, bulk models.BulkItem) {
    bulkID := bulk.BulkID

    // Download all result types
    resultTypes := map[string]string{
        "full":      "complete results",
        "valid":     "verified emails only",
        "not_found": "domains without results",
    }

    for resultType, description := range resultTypes {
        filename := fmt.Sprintf("./domain_search_%d_%s.csv", bulkID, resultType)
        err := client.SaveBulkResults(models.BulkTypeSearch, bulkID, filename, resultType)
        if err == nil {
            fmt.Printf("  ✓ Downloaded %s to %s\n", description, filename)
        } else {
            fmt.Printf("  ✗ Failed to download %s: %v\n", description, err)
        }
    }

    // Mark as used by renaming
    newName := fmt.Sprintf("[PROCESSED] %s", bulk.Name)
    renameParams := &models.BulkRenameParams{Name: newName}
    client.RenameBulk(models.BulkTypeSearch, bulkID, renameParams)
}
```

### Helper Functions

```go
func monitorBulkProgress(client *tomba.Tomba, bulkType models.BulkType, bulkID int64) {
    fmt.Printf("Monitoring progress for bulk ID: %d...\n", bulkID)

    startTime := time.Now()

    for {
        progress, err := client.GetBulkProgress(bulkType, bulkID)
        if err != nil {
            log.Printf("Error getting progress: %v", err)
            time.Sleep(10 * time.Second)
            continue
        }

        elapsed := time.Since(startTime)
        fmt.Printf("Progress: %d%% (%d processed) - Elapsed: %v\n",
            progress.Progress, progress.Processed, elapsed.Round(time.Second))

        if progress.Progress >= 100 {
            fmt.Printf("✓ Domain search completed in %v!\n", elapsed.Round(time.Second))
            break
        }

        time.Sleep(15 * time.Second)
    }
}

func monitorWithEmailCounts(client *tomba.Tomba, bulkType models.BulkType, bulkID int64) {
    fmt.Printf("Monitoring bulk %d with email count tracking...\n", bulkID)

    for {
        progress, err := client.GetBulkProgress(bulkType, bulkID)
        if err != nil {
            log.Printf("Error getting progress: %v", err)
            time.Sleep(15 * time.Second)
            continue
        }

        fmt.Printf("Progress: %d%% | Domains: %d | Emails: %d\n",
            progress.Progress, progress.Processed, progress.ProcessedEmail)

        if progress.Progress >= 100 {
            fmt.Printf("✓ Search completed! Found %d emails from %d domains\n",
                progress.ProcessedEmail, progress.Processed)
            break
        }

        time.Sleep(20 * time.Second)
    }
}
```

### Configuration Options

#### Email Type Filtering

```go
// Personal emails only
EmailType: models.BulkSearchParamsType{
    Type:         "personal",
    PriorityType: "only",
}

// Generic emails only
EmailType: models.BulkSearchParamsType{
    Type:         "generic",
    PriorityType: "only",
}

// All types with personal priority
EmailType: models.BulkSearchParamsType{
    Type:         "all",
    PriorityType: "priority",
}
```

#### Department Targeting

```go
// Engineering teams only
Department: models.BulkSearchParamsDepartment{
    Name:         []string{"engineering", "software", "security"},
    PriorityType: "only",
}

// Exclude specific departments
Department: models.BulkSearchParamsDepartment{
    Name:         []string{"hr", "accounting", "legal"},
    PriorityType: "exclude",
}

// Prioritize business teams
Department: models.BulkSearchParamsDepartment{
    Name:         []string{"sales", "marketing", "business"},
    PriorityType: "priority",
}
```

## Best Practices

- **Clean Domain Lists**: Ensure domains are properly formatted without protocols
- **Set Reasonable Limits**: Balance between comprehensive results and processing time
- **Use Verification**: Enable email verification for higher-quality prospect lists
- **Target Smartly**: Use department and email type filters to focus on relevant contacts
- **Monitor Regularly**: Check progress for large bulk operations
- **Download Multiple Types**: Get full, valid, and not_found results for complete analysis
- **Batch Large Lists**: Process very large domain lists in manageable batches
- **Archive Completed**: Keep dashboard organized by archiving old bulks
- **Track Costs**: Monitor verification costs for budget planning
- **Regular Cleanup**: Archive or delete old bulks to maintain performance

### Common Use Cases

- **Lead Generation**: Build prospect lists for sales outreach
- **Competitor Research**: Analyze competitor contact structures
- **Market Expansion**: Find contacts in new market segments
- **Partnership Development**: Identify potential integration partners
- **Content Marketing**: Build blogger and influencer contact lists
- **Account-Based Marketing**: Deep-dive into target account contacts
- **Industry Analysis**: Study contact patterns across industries

### Result Analysis

The domain search results typically include:

- **Email Address**: Discovered email addresses
- **Name**: Associated contact names when available
- **Department**: Inferred or detected department
- **Job Title**: Contact roles and positions
- **Verification Status**: Email deliverability status
- **Source**: Where the email was discovered
- **Domain**: Source company domain
- **Social Profiles**: Associated social media profiles

