emailr_
Todos los artículos
usecase·8 min

Emails de invitación de equipo: optimización de la conversión

saasinvitationsconversion

Los emails de invitación de equipo son críticos para el crecimiento de un SaaS. Una invitación bien diseñada convierte a los destinatarios en usuarios activos. Aquí tienes cómo optimizar tu flujo de invitaciones.

Anatomía del email de invitación

Elementos esenciales

interface TeamInvitation {
  inviter: {
    name: string;
    email: string;
    avatarUrl?: string;
  };
  organization: {
    name: string;
    logoUrl?: string;
  };
  invitee: {
    email: string;
    role: string;
  };
  invitation: {
    id: string;
    expiresAt: Date;
    message?: string;
  };
}

Plantilla de alta conversión

await sendEmail({
  to: invitee.email,
  subject: `${inviter.name} invited you to join ${org.name}`,
  template: 'team-invitation',
  data: {
    inviter,
    organization: org,
    role: invitee.role,
    personalMessage: invitation.message,
    acceptUrl: `${baseUrl}/invitations/${invitation.id}/accept`,
    expiresAt: invitation.expiresAt,
    previewText: `Join ${org.name} on YourApp`
  }
});

Optimización de la conversión

Prueba social

// Include team context
const teamContext = {
  teamSize: org.memberCount,
  recentActivity: `${org.activeMembers} team members active this week`,
  popularFeatures: await getOrgTopFeatures(org.id)
};

Urgencia sin presión

// Soft expiration
const expirationCopy = {
  '7days': 'This invitation expires in 7 days',
  '3days': 'Expires in 3 days',
  '1day': 'Expires tomorrow',
  'expired': 'This invitation has expired'
};

Secuencia de recordatorios

const invitationReminders = [
  {
    daysAfter: 3,
    subject: `Reminder: ${inviter.name} invited you to ${org.name}`,
    template: 'invitation-reminder-1'
  },
  {
    daysAfter: 6,
    subject: `Your invitation to ${org.name} expires soon`,
    template: 'invitation-reminder-2'
  }
];

async function scheduleReminders(invitation: Invitation) {
  for (const reminder of invitationReminders) {
    await scheduleEmail({
      sendAt: addDays(invitation.createdAt, reminder.daysAfter),
      to: invitation.email,
      subject: reminder.subject,
      template: reminder.template,
      data: { invitation },
      cancelIf: [
        { condition: 'invitation_accepted' },
        { condition: 'invitation_cancelled' }
      ]
    });
  }
}

Invitaciones según el rol

Invitación para administrador

await sendEmail({
  to: invitee.email,
  subject: `You've been invited as an admin of ${org.name}`,
  template: 'admin-invitation',
  data: {
    inviter,
    organization: org,
    role: 'Admin',
    permissions: [
      'Manage team members',
      'Access billing',
      'Configure integrations',
      'View all projects'
    ],
    acceptUrl: `${baseUrl}/invitations/${invitation.id}/accept`
  }
});

Invitación con rol limitado

await sendEmail({
  to: invitee.email,
  subject: `${inviter.name} invited you to collaborate on ${org.name}`,
  template: 'member-invitation',
  data: {
    inviter,
    organization: org,
    role: 'Member',
    accessScope: 'You\'ll have access to projects you\'re added to',
    acceptUrl: `${baseUrl}/invitations/${invitation.id}/accept`
  }
});

Flujo posterior a la aceptación

Bienvenida al equipo

// After invitation accepted
await sendEmail({
  to: newMember.email,
  subject: `Welcome to ${org.name}!`,
  template: 'team-welcome',
  data: {
    member: newMember,
    organization: org,
    invitedBy: inviter,
    gettingStarted: [
      { step: 'Complete your profile', url: `${baseUrl}/settings/profile` },
      { step: 'Explore your projects', url: `${baseUrl}/projects` },
      { step: 'Meet your team', url: `${baseUrl}/team` }
    ],
    helpResources: {
      docs: `${baseUrl}/docs`,
      support: `${baseUrl}/support`
    }
  }
});

Notificar a quien invitó

await sendEmail({
  to: inviter.email,
  subject: `${invitee.name} joined ${org.name}`,
  template: 'invitation-accepted',
  data: {
    inviter,
    newMember: {
      name: invitee.name,
      email: invitee.email,
      role: invitee.role
    },
    teamUrl: `${baseUrl}/team`
  }
});

Manejo de casos límite

Invitación a usuario existente

if (await userExists(invitee.email)) {
  await sendEmail({
    to: invitee.email,
    subject: `${inviter.name} invited you to join ${org.name}`,
    template: 'existing-user-invitation',
    data: {
      inviter,
      organization: org,
      // Different CTA - just accept, no signup
      acceptUrl: `${baseUrl}/invitations/${invitation.id}/accept`,
      note: 'You already have an account. Just click to join.'
    }
  });
}

Invitación enviada al email equivocado

// Allow forwarding to correct email
await sendEmail({
  to: invitee.email,
  template: 'invitation',
  data: {
    // ...
    wrongEmailUrl: `${baseUrl}/invitations/${invitation.id}/wrong-email`,
    wrongEmailNote: 'Not the right email? Let us know.'
  }
});

Mejores prácticas

  1. Contexto claro del remitente - Quién los invitó y por qué
  2. Muestra al equipo - La prueba social aumenta la aceptación
  3. Explica el rol - Qué acceso tendrán
  4. CTA simple - Un botón para aceptar
  5. Recuerda con delicadeza - Máximo 2-3 recordatorios
  6. Rechazo fácil - Permite que rechacen con elegancia
  7. Bienvenida cálida - Gran primera impresión tras la aceptación

Las invitaciones de equipo suelen ser la primera interacción de alguien con tu producto. Haz que cuente.

e_

Escrito por el equipo de emailr

Construyendo infraestructura de email para desarrolladores

¿Listo para empezar a enviar?

Obtén tu clave API y envía tu primer email en menos de 5 minutos. No se requiere tarjeta de crédito.