Skip to content

n8n 第三方服务集成 - 连接常用 SaaS 平台

在现代企业环境中,我们通常需要使用多个 SaaS 平台来完成不同的业务需求。n8n 提供了丰富的第三方服务集成能力,让我们能够轻松连接和自动化这些平台之间的数据流转。

Google Workspace 集成

Google Sheets 操作

Google Sheets 是最常用的在线表格工具,n8n 提供了完整的 Google Sheets 节点支持。

基本配置

json
{
  "authentication": "oAuth2Api",
  "resource": "sheet",
  "operation": "read",
  "documentId": "your-sheet-id",
  "sheetName": "Sheet1",
  "range": "A1:Z1000"
}

读取数据

javascript
// 从 Google Sheets 读取数据并处理
const sheetData = items[0].json;

// 数据清洗和转换
const processedData = sheetData.map(row => ({
  id: row.ID,
  name: row.Name?.trim(),
  email: row.Email?.toLowerCase(),
  status: row.Status || 'pending',
  createdAt: new Date(row['Created At']).toISOString()
}));

// 过滤有效数据
const validData = processedData.filter(item => 
  item.email && item.email.includes('@')
);

return validData.map(item => ({ json: item }));

写入数据

javascript
// 批量写入数据到 Google Sheets
const dataToWrite = items.map(item => [
  item.json.id,
  item.json.name,
  item.json.email,
  item.json.status,
  new Date().toISOString()
]);

// 添加表头
const headers = ['ID', 'Name', 'Email', 'Status', 'Updated At'];
const finalData = [headers, ...dataToWrite];

return [{
  json: {
    range: 'A1:E' + (finalData.length),
    values: finalData
  }
}];

Gmail 自动化

javascript
// Gmail 邮件自动分类和处理
function categorizeEmail(email) {
  const subject = email.subject.toLowerCase();
  const from = email.from.toLowerCase();
  
  // 订单相关邮件
  if (subject.includes('order') || subject.includes('订单')) {
    return {
      category: 'orders',
      priority: 'high',
      action: 'forward_to_sales'
    };
  }
  
  // 客服相关邮件
  if (subject.includes('support') || subject.includes('help')) {
    return {
      category: 'support',
      priority: 'medium',
      action: 'create_ticket'
    };
  }
  
  // 发票相关邮件
  if (subject.includes('invoice') || subject.includes('发票')) {
    return {
      category: 'finance',
      priority: 'high',
      action: 'forward_to_finance'
    };
  }
  
  return {
    category: 'general',
    priority: 'low',
    action: 'archive'
  };
}

const emailData = items[0].json;
const classification = categorizeEmail(emailData);

return [{
  json: {
    ...emailData,
    classification,
    processedAt: new Date().toISOString()
  }
}];

Microsoft 365 集成

Excel Online 操作

javascript
// Microsoft Excel Online 数据处理
async function processExcelData(workbookId, worksheetName) {
  // 读取 Excel 数据
  const excelData = await getExcelData(workbookId, worksheetName);
  
  // 数据分析和处理
  const analysis = {
    totalRows: excelData.length,
    summary: {},
    trends: []
  };
  
  // 按类别统计
  const categoryStats = excelData.reduce((acc, row) => {
    const category = row.Category || 'Unknown';
    if (!acc[category]) {
      acc[category] = { count: 0, total: 0 };
    }
    acc[category].count++;
    acc[category].total += parseFloat(row.Amount || 0);
    return acc;
  }, {});
  
  analysis.summary = categoryStats;
  
  // 生成趋势数据
  const monthlyData = excelData.reduce((acc, row) => {
    const month = new Date(row.Date).toISOString().substring(0, 7);
    if (!acc[month]) acc[month] = 0;
    acc[month] += parseFloat(row.Amount || 0);
    return acc;
  }, {});
  
  analysis.trends = Object.entries(monthlyData).map(([month, amount]) => ({
    month,
    amount
  }));
  
  return analysis;
}

const workbookId = items[0].json.workbookId;
const analysis = await processExcelData(workbookId, 'Data');

return [{ json: analysis }];

Outlook 邮件处理

javascript
// Outlook 邮件自动回复和转发
function generateAutoReply(originalEmail) {
  const templates = {
    support: {
      subject: 'Re: {{ originalSubject }} - 已收到您的咨询',
      body: `
        感谢您的咨询!
        
        我们已收到您的邮件,工单号:{{ ticketId }}
        我们的客服团队将在24小时内回复您。
        
        如有紧急问题,请致电:400-123-4567
        
        此邮件为自动回复,请勿直接回复。
      `
    },
    
    sales: {
      subject: 'Re: {{ originalSubject }} - 销售咨询确认',
      body: `
        感谢您对我们产品的关注!
        
        我们已安排专业的销售顾问为您服务。
        预计将在2个工作日内与您联系。
        
        如需加急处理,请联系:sales@company.com
      `
    }
  };
  
  const emailType = detectEmailType(originalEmail);
  const template = templates[emailType] || templates.support;
  
  const ticketId = generateTicketId();
  
  return {
    to: originalEmail.from,
    subject: template.subject.replace('{{ originalSubject }}', originalEmail.subject),
    body: template.body.replace('{{ ticketId }}', ticketId),
    ticketId
  };
}

function detectEmailType(email) {
  const subject = email.subject.toLowerCase();
  const body = email.body.toLowerCase();
  
  if (subject.includes('price') || subject.includes('buy') || body.includes('purchase')) {
    return 'sales';
  }
  
  return 'support';
}

function generateTicketId() {
  return 'TK' + Date.now().toString().slice(-8);
}

const originalEmail = items[0].json;
const autoReply = generateAutoReply(originalEmail);

return [{ json: autoReply }];

Salesforce 集成

客户数据同步

javascript
// Salesforce 客户数据同步
class SalesforceSync {
  constructor(config) {
    this.config = config;
    this.accessToken = null;
  }
  
  async authenticate() {
    const response = await fetch(`${this.config.loginUrl}/services/oauth2/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: new URLSearchParams({
        grant_type: 'password',
        client_id: this.config.clientId,
        client_secret: this.config.clientSecret,
        username: this.config.username,
        password: this.config.password + this.config.securityToken
      })
    });
    
    const result = await response.json();
    this.accessToken = result.access_token;
    this.instanceUrl = result.instance_url;
  }
  
  async createLead(leadData) {
    if (!this.accessToken) await this.authenticate();
    
    const response = await fetch(`${this.instanceUrl}/services/data/v52.0/sobjects/Lead/`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(leadData)
    });
    
    return await response.json();
  }
  
  async updateAccount(accountId, accountData) {
    if (!this.accessToken) await this.authenticate();
    
    const response = await fetch(`${this.instanceUrl}/services/data/v52.0/sobjects/Account/${accountId}`, {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${this.accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(accountData)
    });
    
    return response.ok;
  }
  
  async queryRecords(soql) {
    if (!this.accessToken) await this.authenticate();
    
    const response = await fetch(
      `${this.instanceUrl}/services/data/v52.0/query/?q=${encodeURIComponent(soql)}`,
      {
        headers: {
          'Authorization': `Bearer ${this.accessToken}`
        }
      }
    );
    
    const result = await response.json();
    return result.records;
  }
}

// 使用 Salesforce 同步
const salesforce = new SalesforceSync({
  loginUrl: 'https://login.salesforce.com',
  clientId: process.env.SF_CLIENT_ID,
  clientSecret: process.env.SF_CLIENT_SECRET,
  username: process.env.SF_USERNAME,
  password: process.env.SF_PASSWORD,
  securityToken: process.env.SF_SECURITY_TOKEN
});

const customerData = items[0].json;

// 创建潜在客户
const leadResult = await salesforce.createLead({
  FirstName: customerData.firstName,
  LastName: customerData.lastName,
  Email: customerData.email,
  Company: customerData.company,
  Phone: customerData.phone,
  LeadSource: 'Website'
});

return [{ json: { leadId: leadResult.id, success: leadResult.success } }];

Slack 深度集成

工作流状态通知

javascript
// Slack 工作流状态通知系统
class SlackWorkflowNotifier {
  constructor(webhookUrl, botToken) {
    this.webhookUrl = webhookUrl;
    this.botToken = botToken;
  }
  
  async sendWorkflowStatus(workflowData) {
    const { name, status, duration, results } = workflowData;
    
    const statusEmoji = {
      success: '✅',
      warning: '⚠️',
      error: '❌',
      running: '🔄'
    };
    
    const statusColor = {
      success: 'good',
      warning: 'warning',
      error: 'danger',
      running: '#36a64f'
    };
    
    const attachment = {
      color: statusColor[status],
      title: `${statusEmoji[status]} 工作流: ${name}`,
      fields: [
        {
          title: '状态',
          value: status.toUpperCase(),
          short: true
        },
        {
          title: '执行时间',
          value: duration,
          short: true
        }
      ],
      footer: 'n8n 自动化平台',
      ts: Math.floor(Date.now() / 1000)
    };
    
    if (results) {
      attachment.fields.push({
        title: '处理结果',
        value: `成功: ${results.success || 0}, 失败: ${results.failed || 0}`,
        short: false
      });
    }
    
    const payload = {
      text: `工作流 ${name} 执行${status === 'success' ? '成功' : '异常'}`,
      attachments: [attachment]
    };
    
    await fetch(this.webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    });
  }
  
  async createChannel(channelName, purpose) {
    const response = await fetch('https://slack.com/api/conversations.create', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.botToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name: channelName,
        purpose: purpose
      })
    });
    
    return await response.json();
  }
  
  async inviteToChannel(channelId, userIds) {
    const response = await fetch('https://slack.com/api/conversations.invite', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.botToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        channel: channelId,
        users: userIds.join(',')
      })
    });
    
    return await response.json();
  }
}

// 使用 Slack 通知
const slackNotifier = new SlackWorkflowNotifier(
  process.env.SLACK_WEBHOOK_URL,
  process.env.SLACK_BOT_TOKEN
);

const workflowStatus = {
  name: '客户数据同步',
  status: 'success',
  duration: '2分30秒',
  results: {
    success: 150,
    failed: 2
  }
};

await slackNotifier.sendWorkflowStatus(workflowStatus);

return [{ json: { notificationSent: true } }];

支付平台集成

Stripe 支付处理

javascript
// Stripe 支付事件处理
function processStripeWebhook(event) {
  const { type, data } = event;
  
  switch (type) {
    case 'payment_intent.succeeded':
      return handlePaymentSuccess(data.object);
      
    case 'payment_intent.payment_failed':
      return handlePaymentFailure(data.object);
      
    case 'customer.subscription.created':
      return handleSubscriptionCreated(data.object);
      
    case 'customer.subscription.deleted':
      return handleSubscriptionCanceled(data.object);
      
    default:
      return { action: 'log', message: `Unhandled event type: ${type}` };
  }
}

function handlePaymentSuccess(paymentIntent) {
  return {
    action: 'fulfill_order',
    orderId: paymentIntent.metadata.order_id,
    amount: paymentIntent.amount / 100,
    currency: paymentIntent.currency,
    customerId: paymentIntent.customer,
    paymentMethod: paymentIntent.payment_method,
    notification: {
      type: 'payment_success',
      message: `Payment of ${paymentIntent.amount / 100} ${paymentIntent.currency} received`
    }
  };
}

function handlePaymentFailure(paymentIntent) {
  return {
    action: 'handle_payment_failure',
    orderId: paymentIntent.metadata.order_id,
    failureReason: paymentIntent.last_payment_error?.message,
    customerId: paymentIntent.customer,
    notification: {
      type: 'payment_failed',
      message: `Payment failed: ${paymentIntent.last_payment_error?.message}`
    }
  };
}

function handleSubscriptionCreated(subscription) {
  return {
    action: 'activate_subscription',
    subscriptionId: subscription.id,
    customerId: subscription.customer,
    planId: subscription.items.data[0].price.id,
    status: subscription.status,
    notification: {
      type: 'subscription_created',
      message: `New subscription created for customer ${subscription.customer}`
    }
  };
}

const stripeEvent = items[0].json;
const result = processStripeWebhook(stripeEvent);

return [{ json: result }];

社交媒体集成

Twitter 自动化

javascript
// Twitter 内容发布和监控
class TwitterAutomation {
  constructor(apiKeys) {
    this.apiKeys = apiKeys;
  }
  
  async postTweet(content, options = {}) {
    const tweetData = {
      text: content,
      ...options
    };
    
    const response = await fetch('https://api.twitter.com/2/tweets', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKeys.bearerToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(tweetData)
    });
    
    return await response.json();
  }
  
  async searchTweets(query, options = {}) {
    const params = new URLSearchParams({
      query: query,
      max_results: options.maxResults || 10,
      'tweet.fields': 'created_at,author_id,public_metrics'
    });
    
    const response = await fetch(`https://api.twitter.com/2/tweets/search/recent?${params}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKeys.bearerToken}`
      }
    });
    
    return await response.json();
  }
  
  async analyzeMentions(mentions) {
    const analysis = {
      total: mentions.length,
      sentiment: { positive: 0, negative: 0, neutral: 0 },
      topKeywords: {},
      engagement: { likes: 0, retweets: 0, replies: 0 }
    };
    
    mentions.forEach(tweet => {
      // 简单的情感分析
      const sentiment = this.analyzeSentiment(tweet.text);
      analysis.sentiment[sentiment]++;
      
      // 关键词提取
      const keywords = this.extractKeywords(tweet.text);
      keywords.forEach(keyword => {
        analysis.topKeywords[keyword] = (analysis.topKeywords[keyword] || 0) + 1;
      });
      
      // 互动数据
      if (tweet.public_metrics) {
        analysis.engagement.likes += tweet.public_metrics.like_count;
        analysis.engagement.retweets += tweet.public_metrics.retweet_count;
        analysis.engagement.replies += tweet.public_metrics.reply_count;
      }
    });
    
    return analysis;
  }
  
  analyzeSentiment(text) {
    const positiveWords = ['good', 'great', 'awesome', 'love', 'excellent'];
    const negativeWords = ['bad', 'terrible', 'hate', 'awful', 'worst'];
    
    const lowerText = text.toLowerCase();
    const positiveCount = positiveWords.filter(word => lowerText.includes(word)).length;
    const negativeCount = negativeWords.filter(word => lowerText.includes(word)).length;
    
    if (positiveCount > negativeCount) return 'positive';
    if (negativeCount > positiveCount) return 'negative';
    return 'neutral';
  }
  
  extractKeywords(text) {
    const words = text.toLowerCase()
      .replace(/[^\w\s]/g, '')
      .split(/\s+/)
      .filter(word => word.length > 3);
    
    const stopWords = ['this', 'that', 'with', 'have', 'will', 'from', 'they', 'been'];
    return words.filter(word => !stopWords.includes(word));
  }
}

// 使用 Twitter 自动化
const twitter = new TwitterAutomation({
  bearerToken: process.env.TWITTER_BEARER_TOKEN
});

// 搜索品牌提及
const mentions = await twitter.searchTweets('@yourcompany OR "your company"', {
  maxResults: 50
});

// 分析提及内容
const analysis = await twitter.analyzeMentions(mentions.data || []);

return [{ json: { mentions: mentions.data, analysis } }];

小结

第三方服务集成是 n8n 的核心优势之一:

  1. OAuth 认证:安全地连接各种 SaaS 平台
  2. 数据同步:实现不同平台间的数据流转
  3. 事件驱动:基于 Webhook 的实时集成
  4. 批量操作:高效处理大量数据
  5. 错误处理:完善的异常处理和重试机制

下一篇文章,我们将学习自定义节点开发,这是扩展 n8n 功能的高级技术。

记住,集成第三方服务时要特别注意 API 限制、认证安全和数据隐私。合理的缓存和批量处理策略能够显著提升集成的效率和稳定性。