Email sending integration via Resend API for the Artalytics platform
Overview
artsend provides transactional email functionality for the Artalytics platform using the Resend API. It’s a pure email service integration without database dependencies, enabling:
- Contact forms - Gallery visitor messages to artists
- Notifications - Waitlist confirmations, pilot program invitations
- Transactional emails - Whitepaper delivery, metrics access grants
- Professional templates - Pre-built, branded HTML email designs
Installation
Install from the Artalytics GitHub organization:
# Requires GITHUB_PAT for private repos
pak::pkg_install("artalytics/artsend")Quick Start
1. Configure API Key
Get your Resend API key from the Resend Dashboard:
# Set environment variable
Sys.setenv(ART_RESEND_KEY = "re_xxxxxxxxxxxxx")
# Verify configuration
artsend::is_resend_configured()
#> [1] TRUEFor persistent configuration, add to .Renviron:
2. Send Contact Form Email
library(artsend)
result <- send_contact_email(
to = "artist@example.com",
visitor_name = "John Doe",
visitor_email = "john@example.com",
message = "I love your artwork! Can we discuss a commission?",
artwork_title = "Sunset Dreams",
artwork_url = "https://cdn.artalytics.app/..."
)
if (result$success) {
message("Email sent! ID: ", result$message_id)
} else {
warning("Failed: ", result$error)
}3. Handle Response
All functions return a standardized response:
list(
success = TRUE, # Logical indicating success
message_id = "abc123", # Resend message ID (if successful)
error = NULL # Error message (if failed)
)Core Functions
Configuration
| Function | Purpose |
|---|---|
get_resend_config() |
Retrieve API configuration from environment |
is_resend_configured() |
Check if API key is set |
Email Sending
| Function | Purpose |
|---|---|
send_contact_email() |
Gallery visitor → artist contact form |
send_waitlist_confirmation() |
Confirm artist pilot program waitlist signup |
send_artist_invitation() |
Invite artist to join pilot program |
send_whitepaper_email() |
Deliver whitepaper (personalized by user type) |
send_investor_welcome() |
Investor welcome package with data room access |
send_metrics_access_confirmation() |
Confirm metrics documentation access request |
send_metrics_access_granted() |
Notify when metrics access is approved |
send_metrics_admin_notification() |
Alert admin of new access request |
Environment Variables
Required
ART_RESEND_KEY Your Resend API key. Obtain from Resend Dashboard.
Production keys start with re_. Test keys start with re_test_.
# Production
Sys.setenv(ART_RESEND_KEY = "re_xxxxxxxxxxxxx")
# Development/Testing
Sys.setenv(ART_RESEND_KEY = "re_test_xxxxxxxxxxxxx")Usage Examples
Contact Form
Send message from gallery visitor to artist:
result <- send_contact_email(
to = "artist@example.com",
visitor_name = "Sarah Johnson",
visitor_email = "sarah@collector.com",
message = "Your piece 'Urban Dreams' resonates deeply with me.",
artwork_title = "Urban Dreams #42",
artwork_url = "https://cdn.artalytics.app/artworks/abc123/thumb.jpg"
)Pilot Program Workflow
# Step 1: Waitlist confirmation (immediate)
send_waitlist_confirmation(
to = "newartist@example.com",
artist_name = "Marcus Chen",
waitlist_id = "wl-12345"
)
# Step 2: Invitation (after approval)
send_artist_invitation(
to = "newartist@example.com",
artist_name = "Marcus Chen",
onboarding_url = "https://artalytics.app/onboarding?token=xyz789"
)Whitepaper Delivery
Personalized by user type:
# For investors
send_whitepaper_email(
to = "partner@vcfirm.com",
user_type = "investor"
)
# For artists
send_whitepaper_email(
to = "artist@example.com",
user_type = "artist"
)Metrics Access Request System
Three-step gated access workflow:
# Step 1: User submits request → Send confirmation
send_metrics_access_confirmation(
to = "analyst@bank.com",
full_name = "Jane Doe",
request_id = "req-12345"
)
# Step 2: Notify admin for review
send_metrics_admin_notification(
request_details = list(
email = "analyst@bank.com",
full_name = "Jane Doe",
company = "Major Bank",
role = "art_lender",
request_id = "req-12345"
)
)
# Step 3: After approval → Grant access
send_metrics_access_granted(
to = "analyst@bank.com",
full_name = "Jane Doe",
access_instructions = "Your access code: MTR-2024-1234"
)Documentation
- Get Started - Configuration, core concepts, quick start
- Quickstart Guide - Step-by-step examples for all workflows
- Advanced Workflows - Metrics access system, Shiny integration, async sending
- Function Reference - Complete API documentation
Error Handling
Functions return standardized error responses:
result <- send_contact_email(...)
if (!result$success) {
# Handle specific errors
if (stringr::str_detect(result$error, "API key not found")) {
# Set ART_RESEND_KEY environment variable
} else if (stringr::str_detect(result$error, "Invalid.*email")) {
# Validate email addresses
} else {
# Log error, retry, alert admin
rdstools::log_err("Email failed: {result$error}")
}
}Common errors:
-
“Resend API key not found” - Set
ART_RESEND_KEYenvironment variable -
“Invalid recipient email format” - Use
validate_email_format()to check inputs - “API error: …” - Check Resend dashboard for delivery status
- “Email sending failed: …” - Network or API issues (implement retry logic)
Integration Patterns
With Database (artcore)
library(data.table)
# Create email log
email_log <- data.table(
email_id = uuid::UUIDgenerate(),
recipient = "artist@example.com",
email_type = "contact_form",
sent_utc = lubridate::now("UTC")
)
# Send email
result <- send_contact_email(...)
# Update log
email_log[, `:=`(
resend_id = if (result$success) result$message_id else NA_character_,
success = result$success,
error_msg = if (is.null(result$error)) NA_character_ else result$error
)]
# Insert to database
cn <- artcore::dbc()
DBI::dbAppendTable(cn, "email_send_log", email_log)
artcore::dbd(cn)With Shiny
# Server logic
observeEvent(input$send_btn, {
shinybusy::show_spinner()
result <- send_contact_email(
to = input$artist_email,
visitor_name = input$name,
visitor_email = input$email,
message = input$message
)
shinybusy::hide_spinner()
if (result$success) {
showNotification("Message sent!", type = "message")
} else {
showNotification(result$error, type = "error")
}
})Testing
Resend provides test mode for development:
# Use test API key
Sys.setenv(ART_RESEND_KEY = "re_test_xxxxxxxxxxxxx")
# Send test emails
result <- send_contact_email(
to = "test@artalytics.app",
visitor_name = "Test User",
visitor_email = "dev@artalytics.app",
message = "Test message"
)
# Test emails appear in Resend dashboard but are not actually deliveredRate Limits
Resend free tier:
- 100 emails/day
- 3,000 emails/month
For production use, upgrade to a paid plan. Implement delays for batch sends:
for (email in email_list) {
result <- send_contact_email(...)
Sys.sleep(0.1) # 100ms delay
}Best Practices
-
Validate inputs - Use
validate_email_format()before sending -
Handle errors gracefully - Always check
result$success - Log all sends - Track to database for monitoring
- Use test keys in dev - Never send real emails from development
- Store API keys securely - Use environment variables, never commit
- Implement retries - Use exponential backoff for transient failures
- Monitor delivery - Check Resend dashboard regularly
Support
- Issues: https://github.com/artalytics/artsend/issues
- Email: support@artalytics.app
- Resend Docs: https://resend.com/docs
