c发邮件

  1 /* base64编码 */
  2 static const char* base64_enc_map = \
  3                                     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  4 int base64_encode( char* dst, size_t* dlen, const unsigned char* src, size_t slen )
  5 {
  6     size_t i, n;
  7     int C1, C2, C3;
  8     char* p;
  9 
 10     if ( slen == 0 )
 11     {
 12         return 0;
 13     }
 14 
 15     n = ( slen << 3 ) / 6;
 16 
 17     switch ( ( slen << 3 ) - ( n * 6 ) )
 18     {
 19         case  2:
 20             n += 3;
 21             break;
 22         case  4:
 23             n += 2;
 24             break;
 25         default:
 26             break;
 27     }
 28 
 29     if ( *dlen < n + 1 )
 30     {
 31         *dlen = n + 1;
 32         return -1;
 33     }
 34 
 35     n = ( slen / 3 ) * 3;
 36     for ( i = 0, p = dst; i < n; i += 3 )
 37     {
 38         C1 = *src++;
 39         C2 = *src++;
 40         C3 = *src++;
 41         *p++ = base64_enc_map[( C1 >> 2 ) & 0x3F];
 42         *p++ = base64_enc_map[( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F];
 43         *p++ = base64_enc_map[( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F];
 44         *p++ = base64_enc_map[C3 & 0x3F];
 45     }
 46 
 47     if ( i < slen )
 48     {
 49         C1 = *src++;
 50         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
 51         *p++ = base64_enc_map[( C1 >> 2 ) & 0x3F];
 52         *p++ = base64_enc_map[( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F];
 53         ( i + 1 ) < slen ? ( *p++ = base64_enc_map[( ( C2 & 15 ) << 2 ) & 0x3F] ) : ( *p++ = '=' );
 54         *p++ = '=';
 55     }
 56 
 57     *dlen = p - dst;
 58     *p = 0;
 59 
 60     return 0;
 61 }
 62 
 63 /* 主动连接 */
 64 static SOCKET tcp_connect( const char* host, unsigned short port = 25, int msec = 100 )
 65 {
 66     int ret;
 67     SOCKET fd;
 68     struct sockaddr_in sin;
 69     struct hostent* h;
 70     unsigned long ul;
 71     struct timeval tv;
 72     struct linger lg;
 73     int nodelay;
 74     fd_set fdset;
 75 
 76     /* 填充服务器地址 */
 77     memset( &sin, 0, sizeof( sin ) );
 78     sin.sin_family = AF_INET;
 79     if ( ( h = gethostbyname( host ) ) == NULL || h->h_addrtype != AF_INET )
 80     {
 81         return INVALID_SOCKET;
 82     }
 83     memcpy( &sin.sin_addr.S_un.S_addr, h->h_addr, h->h_length );
 84     sin.sin_port = htons( port );
 85 
 86 
 87     /* 建socket */
 88     if ( ( fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) ==  INVALID_SOCKET )
 89     {
 90         return INVALID_SOCKET;
 91     }
 92 
 93     /* 设置非阻塞 */
 94     ul = 1;
 95     if ( ioctlsocket( fd, FIONBIO, &ul ) != 0 )
 96     {
 97         closesocket( fd );
 98         return INVALID_SOCKET;
 99     }
100 
101     /* 主动连接 */
102     if ( connect( fd, ( const struct sockaddr* ) &sin, sizeof( sin ) ) != 0 )
103     {
104         FD_ZERO( &fdset );
105         FD_SET( fd, &fdset );
106 
107         memset( &tv, 0, sizeof( tv ) );
108         tv.tv_sec = msec / 1000;
109         tv.tv_usec = ( msec % 1000 ) * 1000;
110 
111         /* 超时或报错 */
112         if ( select( fd + 1, 0, &fdset, 0, &tv ) != 1 )
113         {
114             closesocket( fd );
115             return INVALID_SOCKET;
116         }
117     }
118 
119     /* 置为阻塞 */
120     ul = 0;
121     ret = ioctlsocket( fd, FIONBIO, &ul );
122     assert( ret == 0 );
123 
124     /*消除滞留*/
125     memset( &lg, 0, sizeof( lg ) );
126     ret = setsockopt( fd, SOL_SOCKET, SO_LINGER, ( const char* ) &lg, sizeof( lg ) );
127     assert( ret == 0 );
128 
129     /*禁用合并*/
130     nodelay = 1;
131     ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, ( const char* ) &nodelay, sizeof( nodelay ) );
132     assert( ret == 0 );
133 
134     return fd;
135 }
136 
137 
138 #define RECV(fd, buff, suc) do { \
139         if (recv( (fd), (buff), sizeof( (buff) ), 0 ) <= 0 || \
140                 memcmp((buff), (suc), 3)) \
141         { \
142             closesocket((fd)); \
143             return -1; \
144         } \
145     }while(0)
146 
147 
148 #define SEND(fd, buff, len) do { \
149         register size_t i = (len); \
150         if (send( (fd), (buff), i, 0 ) < (int)i) \
151         { \
152             closesocket((fd)); \
153             return -1; \
154         } \
155     }while(0)
156 
157 
158 /* 发邮件 */
159 int send_mail( const char* server,
160                const char* user, const char* pwd, \
161                const char* sender, const char* receiver, \
162                const char* str, const unsigned char* data, size_t datalen )
163 {
164     SOCKET fd;
165     char buff[1024];
166     size_t len;
167     size_t pos;
168 
169     /* 连接SMTP服务器 */
170     fd = tcp_connect( server );
171     if ( fd == INVALID_SOCKET )
172     {
173         ::MessageBox( NULL, "无法连接服务器,请检查网络设备!", "错误", MB_OK );
174         return -1;
175     }
176 
177     /* 邮件问答 */
178     RECV( fd, buff, "220" );
179 
180     sprintf( buff, "HELO %s\r\n", server );
181     SEND( fd, buff, strlen( buff ) );
182     RECV( fd, buff, "250" );
183 
184     /* 登录过程 */
185     SEND( fd, "AUTH LOGIN\r\n", 12 ); /* 请求登录 */
186     RECV( fd, buff, "334" );
187 
188     len = sizeof( buff );
189     base64_encode( buff, &len, ( const unsigned char* )user, strlen( user ) );
190     strcat( buff, "\r\n" );
191     SEND( fd, buff, len + 2 ); /* 用户名 */
192     RECV( fd, buff, "334" );
193 
194     len = sizeof( buff );
195     base64_encode( buff, &len, ( const unsigned char* )pwd, strlen( pwd ) );
196     strcat( buff, "\r\n" );
197     SEND( fd, buff, len + 2 ); /* 密码 */
198     RECV( fd, buff, "235" );
199 
200     /* 邮件头 */
201     sprintf( buff, "MAIL FROM:<%s>\r\n", sender );
202     SEND( fd, buff, strlen( buff ) ); /* 发送者 */
203     RECV( fd, buff, "250" ); /* 250 Ok... */
204 
205     sprintf( buff, "RCPT TO:<%s>\r\n", receiver );
206     SEND( fd, buff, strlen( buff ) ); /* 接收者 */
207     RECV( fd, buff, "250" );
208 
209     SEND( fd, "DATA\r\n", 6 ); /* 请求发送数据 */
210     RECV( fd, buff, "354" );
211 
212     sprintf( buff, "From:\"javadotest\"<%s>\r\n"
213              "To:\"javado\"<%s>\r\n"
214              "Subject:邮件标题\r\n"
215              "MIME-Version: 1.0\r\n"
216              "Content-Type: multipart/mixed; boundary=\"o0o0o0o0o\"\r\n\r\n", \
217              sender, receiver );
218     SEND( fd, buff, strlen( buff ) );
219 
220 
221     /* 发送邮件内容 */
222     sprintf( buff, "--o0o0o0o0o\r\n"
223              "Content-Type: text/plain; charset=\"gb2312\"\r\n\r\n"
224              "%s\r\n\r\n", str );
225     SEND( fd, buff, strlen( buff ) );
226 
227 
228 
229 
230     /* 发送附件 */
231     strcpy( buff, "--o0o0o0o0o\r\n"
232             "Content-Type: application/octet-stream; name=\"附件.doc\"\r\n"
233             "Content-Transfer-Encoding: base64\r\n"
234             "Content-Disposition: attachment; filename=\"附件.doc\"\r\n\r\n" );
235     SEND( fd, buff, strlen( buff ) );
236     if ( datalen > 0 )
237     {
238         for ( pos = 0; pos < datalen; )
239         {
240             len = sizeof( buff );
241             memset( buff, 0, sizeof( buff ) );
242 
243             if ( datalen - pos >= 765 )
244             {
245                 base64_encode( buff, &len, data + pos, 765 );
246                 strcat( buff, "\r\n" );
247                 SEND( fd, buff, 1022 );
248                 pos += 765;
249             }
250             else
251             {
252                 base64_encode( buff, &len, data + pos, datalen - pos );
253                 strcat( buff, "\r\n" );
254                 SEND( fd, buff, strlen( buff ) );
255                 break;
256             }
257         }
258     }
259 
260 
261 
262     /* 完成发送 */
263     SEND( fd, "--o0o0o0o0o--\r\n.\r\nQUIT\r\n", 24 ); /* 请求退出 */
264     RECV( fd, buff, "250" ); /* 250 Ok */
265 
266     closesocket( fd );
267     return 0;
268 }

 

posted on 2015-04-23 17:05  郁郁思扬  阅读(399)  评论(0编辑  收藏  举报

导航