para crear un evento en calendario con c# y el estándar ics debemos conocer algunos conceptos básicos de este estándar popular, gracias a Apple y sus calendarios.
Usando Icalendar o ics para los amigos
En Icalendar (de ahora en adelante ics) es un estándar que se hizo muy popular gracias a apple y ios, este estándar se hizo tan popular que empresas como google, Microsoft entre otros adoptaron y se usa en el día a día.
iCalendar permite a los usuarios invitar a reuniones o asignar tareas a otros usuarios a través del correo electrónico. El destinatario del mensaje en formato iCalendar (de tener un programa que lo permita) puede responder fácilmente aceptando la invitación, o proponiendo otra fecha y hora para la misma.
wikipedia en español
como todo en este mundo de la informática, va evolucionando y cada vez podemos hacer mas compleja estas invitaciones, podemos hacer algo muy simple (que es lo que vamos a ver en este post) hasta algo muy complicado como el siguiente ejemplo
nosotros vamos a usar el siguiente ejemplo y vamos a programarlo, la ventaja de usar ics es que es un formato muy simple, tan simple que podemos usar un editor de texto y hacerlo manualmente, pero nos gusta hacer la vida más fácil.
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR
lo que vemos en la parte de arriba es lo básico que nos piden para crear un evento en el calendario.
Creando un evento en calendario
Principalmente vamos a usar las siguientes :
- DateTime – Formato de tiempo
- TimeZoneInfo – Conversión e información de la hora y fecha
- Directory – crear elementos en el disco duro
- IO/ StreamWrite – escribir un archivo
- SmtpClient – configuración del cliente para enviar correo electrónico
- MailAddress – formatos para correo electrónico
- MailMessege – envió del contenido y agregar multimedia
- NetworkCredential – configuración para enviar todo el correo electrónico
Clase principal para crear un evento en calendario
en nuestra clase principal (Program.cs) vamos a dividirlo de la siguientes clases:
- Pedir los elementos a llenar
- Creación y transformación de las fechas
- creación del documento
- llamado a enviar email
Console.Write("Introduce email del invitado");
string emailid = Console.ReadLine();
Console.Write("Nombre del invitado");
string nameinv = Console.ReadLine();
Console.Write("\nNombre de organizador");
string nombreorg = Console.ReadLine();
Console.Write("\nEmail de organizador");
string tuEmail = Console.ReadLine();
Console.Write("\nAño inicio");
int anoin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nmes inicio");
int mesin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nDia inicio");
int diain = Convert.ToInt16(Console.ReadLine());
Console.Write("\nHora inicio 0-23");
int horain = Convert.ToInt16(Console.ReadLine());
Console.Write("\nMinutos inicio 0-59");
int minin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nSegundos inicio 0-59");
int segin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nAño fin");
int anofin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nmes fin");
int mesfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nDia fin");
int diafin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nHora fin 0-23");
int horafin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nMin fin 0-59");
int minfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nSegundo fin 0-59");
int segfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nAsunto no max-60");
string asunto = Console.ReadLine();
En el código anterior pedimos los valores requerido por consola, en la parte de las horas pedimos números específicos:
Horas pedimos de 0 a 23, que corresponde a la hora en formato 24h, recordemos que 24 horas no existe si no que es 0 horas.
En los minutos y segundos pedimos de 0 a 59.
si ustedes quieren mejorar más esto, pueden hacer validaciones que realmente se ingrese lo que se pide y no introduzcan texto o algún carácter no deseado.
siguiendo el código anterior llamamos a nuestra clase creadora:
CrearICS cr = new CrearICS();
cr.CreameEsta(emailid, nameinv, nombreorg, tuEmail, asunto, anoin, mesin, diain, horain, minin, segin, anofin, mesfin, diafin, horafin, minfin, segfin);
Console.Write("------------------- \n");
Console.Write("se creo archivo");
Console.Write("\n------------------- \n");
Console.ReadKey();
Clase que convierte las fechas
para crear las fechas validas para el ics necesitamos convertirlas a utc, y en un formato de añomesdiahorasminutossegundosZ.
por esta razón creamos la clase que lo podemos reutilizar varias veces .
algunas clases tienen un poco de humor y son de doble sentido, esto es para hacer mas divertido el código, pueden dejar en los comentarios si no les agrada esto.
class Fechas
{
public String Regresameesta(int ano, int mes, int dia, int hora = 0, int minutos = 0, int segundo = 0)
{
//construimos la fecha actual
DateTime dt2 = new DateTime(ano, mes, dia, hora, minutos, segundo);
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime dateTime;
//convertimos a utc
dateTime = TimeZoneInfo.ConvertTimeToUtc(dt2, TimeZoneInfo.Local);
//regresar
//transformamos al formato que nos pide ics
return dateTime.ToString("yyyyMMddTHHmmssZ");
}
public String Ahorawey()
{
//esta funcion no se usa pero es en caso que elijamos la hora actual
DateTime dth = DateTime.Now;
DateTime dTime;
dTime = TimeZoneInfo.ConvertTimeToUtc(dth, TimeZoneInfo.Local);
return dTime.ToString("yyyyMMddTHHmmssZ");
}
}
En la primera función lo que hacemos es pasar los datos necesarios para crear el formato fecha y transformarlo a utc.
Creación del fiche ics
En esta clase lo que hacemos es lo siguiente, creamos un lugar donde se guardara la ruta de los documentos creados.
string lugar = "./evento/";
System.IO.Directory.CreateDirectory(lugar);
creamos el nombre del documento y asignamos en donde se guarda y comenzamos a escribir
string nombre = "prueba" + DateTime.Now.ToString("ddMMyyyyss") + ".ics";
lugar = System.IO.Path.Combine(lugar, nombre);
using (System.IO.StreamWriter mylogs = System.IO.File.AppendText(lugar))
{
creamos un string que guarde todos los espacios y enter (texto libre) para esto debemos agregar un @ antes del string, como dato curioso, debemos respetar los espacios de la plantilla anterior, si pegamos algún dato o tiene un enter de mas, puede salir con error.
String ics = @"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:"+ email +
"\nDTSTAMP:" + f.Ahorawey() +
"\nORGANIZER; CN="+nombreev+":MAILTO:"+emailor +
"\nDTSTART:" + f.Regresameesta(ast, mast, dast, hast, mnast, sast) +
"\nDTEND:" + f.Regresameesta(aed, med, ded, hed, mned, sed) +
"\nSUMMARY:" + asunto+
"\nGEO:" + "25.6534664;-100.3407974"+
"\nEND:VEVENT" +
"\nEND:VCALENDAR";
mylogs.WriteLine(ics);
mylogs.Close();
}
no se preocupen si no se ve bien (desgraciadamente wordpress actualizo su editor y no puedo usar mi plugin de código) al final de este post dejare el link del repositorio.
por ultimo creado el archivo ics, vamos a enviarlo por correo electrónico al que queremos invitar.
Console.Write("\n------------------- \n");
email mail = new email(email, nombreinv, emailor, nombre, nombreev);
Console.Write("correo enviado");
Este es el código completo de la clase principal
class Program
{
static void Main(string[] args)
{
Fechas f = new Fechas();
Console.Write("Introduce email del invitado");
string emailid = Console.ReadLine();
Console.Write("Nombre del invitado");
string nameinv = Console.ReadLine();
Console.Write("\nNombre de organizador");
string nombreorg = Console.ReadLine();
Console.Write("\nEmail de organizador");
string tuEmail = Console.ReadLine();
Console.Write("\nAño inicio");
int anoin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nmes inicio");
int mesin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nDia inicio");
int diain = Convert.ToInt16(Console.ReadLine());
Console.Write("\nHora inicio 0-23");
int horain = Convert.ToInt16(Console.ReadLine());
Console.Write("\nMinutos inicio 0-59");
int minin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nSegundos inicio 0-59");
int segin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nAño fin");
int anofin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nmes fin");
int mesfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nDia fin");
int diafin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nHora fin 0-23");
int horafin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nMin fin 0-59");
int minfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nSegundo fin 0-59");
int segfin = Convert.ToInt16(Console.ReadLine());
Console.Write("\nAsunto no max-60");
string asunto = Console.ReadLine();
CrearICS cr = new CrearICS();
cr.CreameEsta(emailid, nameinv, nombreorg, tuEmail, asunto, anoin, mesin, diain, horain, minin, segin, anofin, mesfin, diafin, horafin, minfin, segfin);
Console.Write("------------------- \n");
Console.Write("se creo archivo");
Console.Write("\n------------------- \n");
Console.ReadKey();
}
}
class Fechas
{
public String Regresameesta(int ano, int mes, int dia, int hora = 0, int minutos = 0, int segundo = 0)
{
DateTime dt2 = new DateTime(ano, mes, dia, hora, minutos, segundo);
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime dateTime;
dateTime = TimeZoneInfo.ConvertTimeToUtc(dt2, TimeZoneInfo.Local);
//regresar
// dateTime2 = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.FindSystemTimeZoneById(localZone.StandardName));
return dateTime.ToString("yyyyMMddTHHmmssZ");
}
public String Ahorawey()
{
DateTime dth = DateTime.Now;
DateTime dTime;
dTime = TimeZoneInfo.ConvertTimeToUtc(dth, TimeZoneInfo.Local);
return dTime.ToString("yyyyMMddTHHmmssZ");
}
}
class CrearICS
{
public void CreameEsta(string email, string nombreinv, string nombreev, string emailor,string asunto,int ast, int mast, int dast, int hast, int mnast, int sast, int aed, int med, int ded, int hed, int mned, int sed)
{
Fechas f = new Fechas();
//especifico en windows
//string lugar = @"C:\Users\ceflor\Documents\";
//mac y windows
string lugar = "./evento/";
System.IO.Directory.CreateDirectory(lugar);
string nombre = "prueba" + DateTime.Now.ToString("ddMMyyyyss") + ".ics";
lugar = System.IO.Path.Combine(lugar, nombre);
using (System.IO.StreamWriter mylogs = System.IO.File.AppendText(lugar))
{
String ics = @"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:"+ email +
"\nDTSTAMP:" + f.Ahorawey() +
"\nORGANIZER; CN="+nombreev+":MAILTO:"+emailor +
"\nDTSTART:" + f.Regresameesta(ast, mast, dast, hast, mnast, sast) +
"\nDTEND:" + f.Regresameesta(aed, med, ded, hed, mned, sed) +
"\nSUMMARY:" + asunto+
"\nGEO:" + "25.6534664;-100.3407974"+
"\nEND:VEVENT" +
"\nEND:VCALENDAR";
mylogs.WriteLine(ics);
mylogs.Close();
}
Console.Write("\n------------------- \n");
email mail = new email(email, nombreinv, emailor, nombre, nombreev);
Console.Write("correo enviado");
}
}
Creando nuestra función envió de correo electrónico con c# y net core
en esta función vamos a enviar el correo electrónico del invitado, pasaremos información de quien lo invita la url del evento que acabamos de crear, esto es tan personalizable como quieran.
los primeros, configuramos nuestro cliente de correo electrónico, en este caso yo uso hostinger y me dan estos puertos para no complicarme la vida y enviar emails.
//puerto para enviar correo
SmtpClient client = new SmtpClient("mx1.hostinger.mx", 587);
client.EnableSsl = true;
configuramos nuestro correo que vamos a enviar y luego quien va a recibir el correo
//email que envia
MailAddress from = new MailAddress("pruebas@unprogramador.com", "Pruebas un programador");
MailAddress to = new MailAddress(emailInvitar, nombre);
con mailMessage configuramos quien envia y quien recibe (con formato MailAndress) y tenemos la opcion de agregar un documento, un asunto y hasta copia
MailMessage msn = new MailMessage(from, to);
msn.Body = "Hola "+nombre+" Se te hace una invitacion para un evento departe de " + nombreOrganizador + " <" + emailOrganizador + ">" + " solo da click en el archivo con extension ics para agregarlo a tu calendario .\n gracias!";
msn.Attachments.Add(new Attachment("./evento/"+archivo));
msn.Subject = "Invitacion de "+nombreOrganizador+"<"+ emailOrganizador+">";
//hago una copia
msn.CC.Add(new MailAddress("shingrey@unprogramador.com"));
al final enviamos sin antes poner nuestras credenciales de nuestro correo que va a enviar
//credenciales
NetworkCredential myCreds = new NetworkCredential("pruebas@unprogramador.com", "contraseña", "");
client.Credentials = myCreds;
try
{
client.Send(msn);
}
catch (Exception ex)
{
Console.WriteLine("Exception is:" + ex.ToString());
}
Este el código completo de email:
namespace crearics
{
class email
{
public email(String emailInvitar, String nombre, String emailOrganizador, String archivo,String nombreOrganizador)
{
//puerto para enviar correo
SmtpClient client = new SmtpClient("mx1.hostinger.mx", 587);
client.EnableSsl = true;
//email que envia
MailAddress from = new MailAddress("pruebas@unprogramador.com", "Pruebas un programador");
MailAddress to = new MailAddress(emailInvitar, nombre);
MailMessage msn = new MailMessage(from, to);
msn.Body = "Hola "+nombre+" Se te hace una invitacion para un evento departe de " + nombreOrganizador + " <" + emailOrganizador + ">" + " solo da click en el archivo con extension ics para agregarlo a tu calendario .\n gracias!";
msn.Attachments.Add(new Attachment("./evento/"+archivo));
msn.Subject = "Invitacion de "+nombreOrganizador+"<"+ emailOrganizador+">";
//hago una copia
msn.CC.Add(new MailAddress("shingrey@unprogramador.com"));
//credenciales
NetworkCredential myCreds = new NetworkCredential("pruebas@unprogramador.com", "contraseña", "");
client.Credentials = myCreds;
try
{
client.Send(msn);
}
catch (Exception ex)
{
Console.WriteLine("Exception is:" + ex.ToString());
}
}
}
}
el resultado es el siguiente
y lo recibimos de la siguiente manera
esto lo podemos visualizar en cualquier smarthphone y como ven, el código lo comencé a hacer en windows 10 y lo termine y compile en una mac.
Les dejo la url de mi repositorio:
Repositorio de Cesar Flores (shingrey) – crearics